android P 窗口管理WMS 1 ---WindowManagerService概述

╄→гoц情女王★ 提交于 2020-02-26 14:42:18

 

一、WindowManagerService 窗口管理员

窗口的概念,直观的看,是一个界面,比如桌面、打开的一张照片。

从SurfaceFlinger的角度看,它是一个layer,当向surfaceflinger申请一个surface时,实际是创建了一个layer,承载着跟窗口有关的数据。

从WindowManagerService的角度看,它是windowState,管理着窗口有关的状态。

WindowManagerService除了管理着系统中所有的窗口外,还有一个重要功能就是负责事件的分发。因为它管理着系统的所有窗口,所以当有一个事件到来时,WMS最有可能知道哪个窗口适合处理这个事件。
 

1. WindowManagerService的启动。

WMS是由systemServer启动的系统服务的一种。

SystemServer.java
/**
     * Starts a miscellaneous grab bag of stuff that has yet to be refactored and organized.
     */
    private void startOtherServices() {
        final Context context = mSystemContext;
        ...
        WindowManagerService wm = null;
        //先实例化一个InputManagerService对象,作为WindowManagerService 的参数,InputManagerService负责事件的接收分发。
        inputManager = new InputManagerService(context);
        ...
        wm = WindowManagerService.main(context, inputManager, !mFirstBoot, mOnlyCore,
                    (WindowManagerPolicy)OpPhoneWindowManagerInjector.getInstance(), mActivityManagerService.mActivityTaskManager);
        //注册到ServiceManager中。
        ServiceManager.addService(Context.WINDOW_SERVICE, wm, /* allowIsolated= */ false,
                    DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PROTO);
        ServiceManager.addService(Context.INPUT_SERVICE, inputManager,
                    /* allowIsolated= */ false, DUMP_FLAG_PRIORITY_CRITICAL);
        ...
}

WindowManagerService是在一个单独的线程中运行的,而且是以同步(runWithScissors)的方式启动的这个线程,所以在WindowManagerService启动完成之后,SystemServer才能继续往下走。

WindowManagerService.java
    public static WindowManagerService main(final Context context, final InputManagerService im,
            final boolean showBootMsgs, final boolean onlyCore, WindowManagerPolicy policy,
            ActivityTaskManagerService atm) {
        return main(context, im, showBootMsgs, onlyCore, policy, atm,
                SurfaceControl.Transaction::new);
    }

    /**
     * Creates and returns an instance of the WindowManagerService. This call allows the caller
     * to override the {@link TransactionFactory} to stub functionality under test.
     */

    @VisibleForTesting
    public static WindowManagerService main(final Context context, final InputManagerService im,
            final boolean showBootMsgs, final boolean onlyCore, WindowManagerPolicy policy,
            ActivityTaskManagerService atm, TransactionFactory transactionFactory) {
        DisplayThread.getHandler().runWithScissors(() ->
                sInstance = new WindowManagerService(context, im, showBootMsgs, onlyCore, policy,
                        atm, transactionFactory), 0);
        return sInstance;
    }


    // -------------------------------------------------------------
    // Async Handler
    // -------------------------------------------------------------

    final class H extends android.os.Handler {
        ...
    }

WMS所在的线程就是DisplayThread这个显示线程,这个线程不仅被WMS使用,DisplayManagerService、InputManagerService也会使用。当实例化WindowManagerService时,它的成员变量mH就与DisplayThread产生了关联,后期可以通过mH这个handler投递事件到DisplayThread的looper队列中。mH是WMS的内部类H。
 

2. 应用程序、WMS、AMS之间的关系

应用程序的启动,通常是Activity的启动,因为Activity是主要用于UI显示的组件,所以必然跟WMS产生关联。

1)Activity到AMS,未完待续。

2)应用程序到WMS,参见android P View 框架1---概述

3)前面提到接口多数是基于AIDL实现的BinderServer,用于应用进程跟系统进程间跨进程交互。

WMS和AMS都在SystemServer进程,是可以直接进行函数调用的,比如在SystemServer.java中:

SystemServer.java
private void startOtherServices() {
    ...
    mActivityManagerService.setWindowManager(wm);
    ...

}

AMS通过setWindowManager把WMS的句柄wm设置给了AMS中的成员mWindowManager。

ActivityManagerService.java
public void setWindowManager(WindowManagerService wm) {
        synchronized (this) {
            mWindowManager = wm;
            mActivityTaskManager.setWindowManager(wm);

            ...
        }
    }

 WMS中有一个AppWindowToken对应了AMS中的ActivityRecord,

/**
 * Version of WindowToken that is specifically for a particular application (or
 * really activity) that is displaying windows.
 */
class AppWindowToken extends WindowToken implements WindowManagerService.AppFreezeListener,
        ConfigurationContainerListener {
        ...
        // Non-null only for application tokens.
        final IApplicationToken appToken;
        ...
        // TODO: Remove after unification
        ActivityRecord mActivityRecord;
}

/**
 * An entry in the history stack, representing an activity.
 */
public final class ActivityRecord extends ConfigurationContainer {
        ...
        final IApplicationToken.Stub appToken; // window manager token
        // TODO: Remove after unification
        AppWindowToken mAppWindowToken;
        ...
}

这个AppWindowToken是在startActivity的过程中添加的,具体过程如下:

ActivityStack.java
void startActivityLocked(ActivityRecord r, ActivityRecord focusedTopActivity,
            boolean newTask, boolean keepCurTransition, ActivityOptions options) {
        TaskRecord rTask = r.getTaskRecord();
        final int taskId = rTask.taskId;
        // mLaunchTaskBehind tasks get placed at the back of the task stack.
        if (!r.mLaunchTaskBehind && (taskForIdLocked(taskId) == null || newTask)) {
            // Last activity in task had been removed or ActivityManagerService is reusing task.
            // Insert or replace.
            // Might not even be in.
            insertTaskAtTop(rTask, r);
        }
        TaskRecord task = null;
        if (!newTask) {
            // If starting in an existing task, find where that is...
            boolean startIt = true;
            for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
                task = mTaskHistory.get(taskNdx);
                if (task.getTopActivity() == null) {
                    // All activities in task are finishing.
                    continue;
                }
                if (task == rTask) {
                    // Here it is!  Now, if this is not yet visible to the
                    // user, then just add it without starting; it will
                    // get started when the user navigates back to it.
                    if (!startIt) {
                        if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to task "
                                + task, new RuntimeException("here").fillInStackTrace());
                        //创建AppWindowToken对象
                        r.createAppWindowToken();
                        ActivityOptions.abort(options);
                        return;
                    }
                    break;
                } else if (task.numFullscreen > 0) {
                    startIt = false;
                }
            }
        }
        ...
}

ActivityRecord.java
void createAppWindowToken() {
        ...

        // TODO: remove after unification
        mAppWindowToken = mAtmService.mWindowManager.mRoot.getAppWindowToken(appToken.asBinder());
        if (mAppWindowToken != null) {
            // TODO: Should this throw an exception instead?
            Slog.w(TAG, "Attempted to add existing app token: " + appToken);
        } else {
            //获取或创建相应的Task
            final Task container = task.getTask();
            if (container == null) {
                throw new IllegalArgumentException("createAppWindowToken: invalid task =" + task);
            }
            mAppWindowToken = createAppWindow(mAtmService.mWindowManager, appToken,
                    task.voiceSession != null, container.getDisplayContent(),
                    ActivityTaskManagerService.getInputDispatchingTimeoutLocked(this)
                            * 1000000L, fullscreen,
                    (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0, appInfo.targetSdkVersion,
                    info.screenOrientation, mRotationAnimationHint,
                    mLaunchTaskBehind, isAlwaysFocusable());
            ...
            //将该Token添加到对应的Task中。
            container.addChild(mAppWindowToken, Integer.MAX_VALUE /* add on top */);
        }

        task.addActivityToTop(this);

        ...
}

Task.java
class Task extends WindowContainer<AppWindowToken> implements ConfigurationContainerListener{
    ...
    @Override
    void addChild(AppWindowToken wtoken, int position) {
        position = getAdjustedAddPosition(position);
        super.addChild(wtoken, position);
        mDeferRemoval = false;
    }
    ...
}

WindowContainer.java
/**
 * Defines common functionality for classes that can hold windows directly or through their
 * children in a hierarchy form.
 * The test class is {@link WindowContainerTests} which must be kept up-to-date and ran anytime
 * changes are made to this class.
 */
class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<E>
        implements Comparable<WindowContainer>, Animatable {
    ...
    // List of children for this window container. List is in z-order as the children appear on
    // screen with the top-most window container at the tail of the list.
    protected final WindowList<E> mChildren = new WindowList<E>();
    ...
    /**
     * Adds the input window container has a child of this container in order based on the input
     * comparator.
     * @param child The window container to add as a child of this window container.
     * @param comparator Comparator to use in determining the position the child should be added to.
     *                   If null, the child will be added to the top.
     */
    @CallSuper
    protected void addChild(E child, Comparator<E> comparator) {
        ...

        int positionToAdd = -1;
        if (comparator != null) {
            final int count = mChildren.size();
            for (int i = 0; i < count; i++) {
                if (comparator.compare(child, mChildren.get(i)) < 0) {
                    positionToAdd = i;
                    break;
                }
            }
        }

        if (positionToAdd == -1) {
            mChildren.add(child);
        } else {
            mChildren.add(positionToAdd, child);
        }
        onChildAdded(child);

        // Set the parent after we've actually added a child in case a subclass depends on this.
        child.setParent(this);
    }
}


RootWindowContainer.java
/** Root {@link WindowContainer} for the device. */
class RootWindowContainer extends WindowContainer<DisplayContent>
        implements ConfigurationContainerListener {
        ...
        /**
     * Returns the app window token for the input binder if it exist in the system.
     * NOTE: Only one AppWindowToken is allowed to exist in the system for a binder token, since
     * AppWindowToken represents an activity which can only exist on one display.
     */
    AppWindowToken getAppWindowToken(IBinder binder) {
        for (int i = mChildren.size() - 1; i >= 0; --i) {
            final DisplayContent dc = mChildren.get(i);
            final AppWindowToken atoken = dc.getAppWindowToken(binder);
            if (atoken != null) {
                return atoken;
            }
        }
        return null;
    }

    /** Returns the window token for the input binder if it exist in the system. */
    WindowToken getWindowToken(IBinder binder) {
        for (int i = mChildren.size() - 1; i >= 0; --i) {
            final DisplayContent dc = mChildren.get(i);
            final WindowToken wtoken = dc.getWindowToken(binder);
            if (wtoken != null) {
                return wtoken;
            }
        }
        return null;
    }
        ...
}


WindowManagerService.java
// The root of the device window hierarchy.
RootWindowContainer mRoot;
/**
     * Hint to a token that its activity will relaunch, which will trigger removal and addition of
     * a window.
     * @param token Application token for which the activity will be relaunched.
     */
    public void setWillReplaceWindow(IBinder token, boolean animate) {
        synchronized (mGlobalLock) {
            final AppWindowToken appWindowToken = mRoot.getAppWindowToken(token);
            ...
            appWindowToken.setWillReplaceWindows(animate);
        }
    }

 

4)在把一个窗口通过addView注册到WMS后,wms会请surfaceflinger申请一个surface承载UI数据,使窗口内容可以显示到屏幕上。窗口的拥有者通过WindowManagerImpl.java,进一步通过WindowManagerGlobal.java管理名下所有的窗口,具体就是mViews,mRoots,mParams三个列表。

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!