Android6.0 WMS(一) WMS和应用进程的关系

之前在分析Activity的时候有很多和WMS相关的,我们这里再简单总结下和WMS相关的那部分。


一、appToken在WMS中创建

在博客http://blog.csdn.net/kc58236582/article/details/52413871中在APPWindowToken创建过程这节中,我们分析到在AMS调用startActivityLocked的时候,会调用WMS的addAppToken来创建一个APPWindowToken。

    final void startActivityLocked(ActivityRecord r, boolean newTask,
            boolean doResume, boolean keepCurTransition, Bundle options) {
        TaskRecord rTask = r.task;
        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);
            mWindowManager.moveTaskToTop(taskId);
        }
        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 == r.task) {
                    // 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());
                        task.addActivityToTop(r);
                        r.putInHistory();
                        mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken,
                                r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
                                (r.info.flags & ActivityInfo.FLAG_SHOW_FOR_ALL_USERS) != 0,
                                r.userId, r.info.configChanges, task.voiceSession != null,
                                r.mLaunchTaskBehind);
我们再来看看WMS的addAppToken函数,在WMS中创建了APPWindowToken然后保存在mTokenMap中。

    public void addAppToken(int addPos, IApplicationToken token, int taskId, int stackId,
            int requestedOrientation, boolean fullscreen, boolean showForAllUsers, int userId,
            int configChanges, boolean voiceInteraction, boolean launchTaskBehind) {
        ......
        synchronized(mWindowMap) {
            AppWindowToken atoken = findAppWindowToken(token.asBinder());//如果已经有了直接退出
            if (atoken != null) {
                Slog.w(TAG, "Attempted to add existing app token: " + token);
                return;
            }
            atoken = new AppWindowToken(this, token, voiceInteraction);//新建一个APPWindowToken
            atoken.inputDispatchingTimeoutNanos = inputDispatchingTimeoutNanos;
            atoken.appFullscreen = fullscreen;
            atoken.showForAllUsers = showForAllUsers;
            atoken.requestedOrientation = requestedOrientation;
            atoken.layoutConfigChanges = (configChanges &
                    (ActivityInfo.CONFIG_SCREEN_SIZE | ActivityInfo.CONFIG_ORIENTATION)) != 0;
            atoken.mLaunchTaskBehind = launchTaskBehind;
            if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG, "addAppToken: " + atoken
                    + " to stack=" + stackId + " task=" + taskId + " at " + addPos);

            Task task = mTaskIdToTask.get(taskId);
            if (task == null) {
                task = createTaskLocked(taskId, stackId, userId, atoken);
            }
            task.addAppToken(addPos, atoken);

            mTokenMap.put(token.asBinder(), atoken);//保存在mTokenMap中 token为key(Activity的binder对象)

            // Application tokens start out hidden.
            atoken.hidden = true;
            atoken.hiddenRequested = true;
        }
    }

再来看看AppWindowToken的构造函数,它是WindowToken的子类,再调用父类构造函数的时候说明了自己是TYPE_APPLICATION类型的。参数_token指向的是一个ActivityRecord对象的IBinder接口,因此,AppWindowToken类的成员变量appToken描述的就是一个ActivityRecord对象。

    AppWindowToken(WindowManagerService _service, IApplicationToken _token,
            boolean _voiceInteraction) {
        super(_service, _token.asBinder(),
                WindowManager.LayoutParams.TYPE_APPLICATION, true);
        appWindowToken = this;
        appToken = _token;
        voiceInteraction = _voiceInteraction;
        mInputApplicationHandle = new InputApplicationHandle(this);
        mAnimator = service.mAnimator;
        mAppAnimator = new AppWindowAnimator(this);
    }

二、Activity的attach函数

首先在博客http://blog.csdn.net/kc58236582/article/details/52397657中主要分析了Activity的创建 初始化。

handleLaunchActivity函数先调用performLaunchActivity函数,再调用handleResumeActivity函数。

在performLaunchActivity函数先新建Activity,然后调用其attach函数,最后调用了Activity的onCreate函数。

在Activity的attach函数中,主要代码如下:

	......
        mWindow = new PhoneWindow(this);//新建PhoneWindow对象
        mWindow.setCallback(this);//这window中设置回调,在按键事件分发的时候中用到。如果有这个回调,就调用Activity的dispatchKeyEvent
        mWindow.setOnWindowDismissedCallback(this);
	......
	mWindow.setWindowManager(
		(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
		mToken, mComponent.flattenToString(),
		(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
        if (mParent != null) {
            mWindow.setContainer(mParent.getWindow());
        }
        mWindowManager = mWindow.getWindowManager();


三、创建ViewRootImpl、DecorView

我们继续分析,在http://blog.csdn.net/kc58236582/article/details/52411791博客,我们分析到了ViewRootImpl和DecorView的创建。

一般在Activity的onCreate函数中会调用setContentView。而在setContentView会创建DecorView对象。

下面我们再从ActivityThread的handleResumeActivity函数看,先调用了performResumeActivity函数来查找这个Activity,后面主要调用了WindowManager的addView函数。

    final void handleResumeActivity(IBinder token,
            boolean clearHide, boolean isForward, boolean reallyResume) {
        // If we are getting ready to gc after going to the background, well
        // we are back active so skip it.
        unscheduleGcIdler();
        mSomeActivitiesChanged = true;

        // TODO Push resumeArgs into the activity for consideration
        ActivityClientRecord r = performResumeActivity(token, clearHide);

        if (r != null) {
            final Activity a = r.activity;

            if (localLOGV) Slog.v(
                TAG, "Resume " + r + " started activity: " +
                a.mStartedActivity + ", hideForNow: " + r.hideForNow
                + ", finished: " + a.mFinished);

            final int forwardBit = isForward ?
                    WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION : 0;

            // If the window hasn't yet been added to the window manager,
            // and this guy didn't finish itself or start another activity,
            // then go ahead and add the window.
            boolean willBeVisible = !a.mStartedActivity;
            if (!willBeVisible) {
                try {
                    willBeVisible = ActivityManagerNative.getDefault().willActivityBeVisible(
                            a.getActivityToken());
                } catch (RemoteException e) {
                }
            }
            if (r.window == null && !a.mFinished && willBeVisible) {
                r.window = r.activity.getWindow();
                View decor = r.window.getDecorView();
                decor.setVisibility(View.INVISIBLE);
                ViewManager wm = a.getWindowManager();
                WindowManager.LayoutParams l = r.window.getAttributes();
                a.mDecor = decor;
                l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
                l.softInputMode |= forwardBit;
                if (a.mVisibleFromClient) {
                    a.mWindowAdded = true;
                    wm.addView(decor, l);
                }

我们来看WindowManagerImpl的addView函数,其实就是调用了WindowManagerGlobal的addView函数

    @Override
    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyDefaultToken(params);
        mGlobal.addView(view, params, mDisplay, mParentWindow);
    }

之前也分析过WindowManagerGlobal,它有3个重要的成员变量:

    private final ArrayList mViews = new ArrayList();//所有的DecorView对象
    private final ArrayList mRoots = new ArrayList();//所有的ViewRootImpl对象
    private final ArrayList mParams =//所有顶层View的layout参数
            new ArrayList();

们再来看WindowManagerGlobal的addView函数,这个函数先是查找是否已经在WindowManagerGlobal中已经有这个view,如果有的话就调用其ViewRootImpl的doDie函数中主要是调用WindowManagerGlobal函数去除这个ViewRootImpl对象,在这个主要是创建了ViewRootImpl,并且把DecorView,RootViewRootImpl,layout参数都保存起来了。然后调用了ViewRootImpl的setView函数。

    public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow) {
        ......
        int index = findViewLocked(view, false);//查找是否有该view,获取其index
            if (index >= 0) {
                if (mDyingViews.contains(view)) {
                    // Don't wait for MSG_DIE to make it's way through root's queue.
                    mRoots.get(index).doDie();//调用ViewRootImpl的doDie函数
                } else {
                    throw new IllegalStateException("View " + view
                            + " has already been added to the window manager.");
                }
                // The previous removeView() had not completed executing. Now it has.
            }
        ......

            root = new ViewRootImpl(view.getContext(), display);//新建ViewRootImpl对象

            view.setLayoutParams(wparams);

            mViews.add(view);//成员变量增加
            mRoots.add(root);
            mParams.add(wparams);
        }

        // do this last because it fires off messages to start doing things
        try {
            root.setView(view, wparams, panelParentView);//调用ViewRootImpl的setView函数
        } catch (RuntimeException e) {
            // BadTokenException or InvalidDisplayException, clean up.
            synchronized (mLock) {
                final int index = findViewLocked(view, false);
                if (index >= 0) {
                    removeViewLocked(index, true);
                }
            }
            throw e;
        }
    }            


四、ViewRootImpl的setView函数

上面在创建完ViewRootImpl之后会调用其setView函数,setView函数主要可以分成两个部分。


4.1 requestLayout函数

在setView中先会调用requestLayout函数,这个函数在http://blog.csdn.net/kc58236582/article/details/52421683博客中有详细分析,主要调用了WMS的relayoutWindow函数,然后通过SurfaceFlinger来创建一个Surface


4.2 addToDisplay

另一部分就是如下代码,最终会调用WMS的addWindow函数,增加窗口。在http://blog.csdn.net/kc58236582/article/details/52413871博客中WindowState的创建过程那节中有详细分析。

                    res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                            getHostVisibility(), mDisplay.getDisplayId(),
                            mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                            mAttachInfo.mOutsets, mInputChannel);




你可能感兴趣的:(android,WMS)