WindowManagerService几个重要函数分析

文章零散记录自己在学习WMS的一点理解,供日后回顾。

1、prepareAppTransition()

一个设置Activity过渡动画类型函数。ActivityStack.resumeTopActivityLocked();startActivityLocked();moveTaskToFrontLocked();moveTaskToBackLocked()-->WMS.prepareAppTransition()-->AppTransition.setAppTransition()-->mNextAppTransition = transit;这些调用逻辑可以看出AMS那边会根据启动或关闭的不同类型Activity通过调用WMS.prepareAppTransition()来设置mNextAppTransition值。

  public void prepareAppTransition(int transit, boolean alwaysKeepCurrent) {
        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
                "prepareAppTransition()")) {
            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
        }

        synchronized(mWindowMap) {
            if (DEBUG_APP_TRANSITIONS) Slog.v(
                    TAG, "Prepare app transition: transit=" + transit
                    + " " + mAppTransition
                    + " alwaysKeepCurrent=" + alwaysKeepCurrent
                    + " Callers=" + Debug.getCallers(3));
            if (okToDisplay()) {
                if (!mAppTransition.isTransitionSet() || mAppTransition.isTransitionNone()) {
                    mAppTransition.setAppTransition(transit);
                } else if (!alwaysKeepCurrent) {
                    if (transit == AppTransition.TRANSIT_TASK_OPEN
                            && mAppTransition.isTransitionEqual(
                                    AppTransition.TRANSIT_TASK_CLOSE)) {
                        // Opening a new task always supersedes a close for the anim.
                        mAppTransition.setAppTransition(transit);
                    } else if (transit == AppTransition.TRANSIT_ACTIVITY_OPEN
                            && mAppTransition.isTransitionEqual(
                                AppTransition.TRANSIT_ACTIVITY_CLOSE)) {
                        // Opening a new activity always supersedes a close for the anim.
                        mAppTransition.setAppTransition(transit);
                    }
                }
                mAppTransition.prepare();
                mStartingIconInTransition = false;
                mSkipAppTransitionAnimation = false;
                mH.removeMessages(H.APP_TRANSITION_TIMEOUT);
                mH.sendEmptyMessageDelayed(H.APP_TRANSITION_TIMEOUT, 5000);
            }
        }
    }
代码逻辑很简单,如果mAppTransition没有初始化过mNextAppTransition值,或mNextAppTransition值为无动画类型,那么直接设置mNextAppTransition = transit;参数alwaysKeepCurrent表示保持当前已有的动画类型不更改,在为false即可以更改的情况下,如果前一次设置为TRANSIT_TASK_CLOSE,这一次要设置为TRANSIT_TASK_OPEN,此时需要更新动画类型,或是前一次设置为TRANSIT_ACTIVITY_CLOSE,这一次设置为TRANSIT_ACTIVITY_OPEN,此时也需要更新动画类型。设置完成后会调用mAppTransition.prepare()来设置过渡动画状态mAppTransitionState 为APP_STATE_IDLE。

2、updateRotationUncheckedLocked()

这个函数值得深入理解。

  * Updates the current rotation.
     *
     * Returns true if the rotation has been changed.  In this case YOU
     * MUST CALL sendNewConfiguration() TO UNFREEZE THE SCREEN.
更新屏幕旋转信息。
public boolean updateRotationUncheckedLocked(boolean inTransaction) {
        if (mDeferredRotationPauseCount > 0) {
            // Rotation updates have been paused temporarily.  Defer the update until
            // updates have been resumed.
            if (DEBUG_ORIENTATION) Slog.v(TAG, "Deferring rotation, rotation is paused.");
            return false;
        }

        ScreenRotationAnimation screenRotationAnimation =
                mAnimator.getScreenRotationAnimationLocked(Display.DEFAULT_DISPLAY);   //获取屏幕旋转动画对象,验证是否正在播放旋转动画,如果正在播放旋转动画,那么放弃此时update,那放弃后是否出现逻辑问题呢?没关系,动画播完、屏幕解冻后又会重新调用此函数,防止出现逻辑错误。
        if (screenRotationAnimation != null && screenRotationAnimation.isAnimating()) {
            // Rotation updates cannot be performed while the previous rotation change
            // animation is still in progress.  Skip this update.  We will try updating
            // again after the animation is finished and the display is unfrozen.
            if (DEBUG_ORIENTATION) Slog.v(TAG, "Deferring rotation, animation in progress.");
            return false;
        }
        if (!mDisplayEnabled && !mIsUpdateIpoRotation) {    //禁止横屏,那么就无需更新屏幕旋转了。
            // No point choosing a rotation if the display is not enabled.
            if (DEBUG_ORIENTATION) Slog.v(TAG, "Deferring rotation, display is not enabled.");
            return false;
        }

        // TODO: Implement forced rotation changes.
        //       Set mAltOrientation to indicate that the application is receiving
        //       an orientation that has different metrics than it expected.
        //       eg. Portrait instead of Landscape.

        int rotation = (mIsUpdateIpoRotation || mIsUpdateAlarmBootRotation)? Surface.ROTATION_0 : mPolicy.rotationForOrientationLw(mForcedAppOrientation, mRotation);
        boolean altOrientation = !mPolicy.rotationHasCompatibleMetricsLw(
                mForcedAppOrientation, rotation);   //按策略算出屏幕旋转情况,包括传感器方向,应用强制方向等。

        if (DEBUG_ORIENTATION) {
            Slog.v(TAG, "Application requested orientation "
                    + mForcedAppOrientation + ", got rotation " + rotation
                    + " which has " + (altOrientation ? "incompatible" : "compatible")
                    + " metrics");
        }

        if (mRotation == rotation && mAltOrientation == altOrientation) {   //如果方向没有更改,直接返回。
            // No change.
            return false;
        }

        Slog.v(TAG,
            "Rotation changed to " + rotation + (altOrientation ? " (alt)" : "")
            + " from " + mRotation + (mAltOrientation ? " (alt)" : "")
            + ", forceApp=" + mForcedAppOrientation);
                                                          //以下逻辑是方向更改后所走的逻辑:
        mRotation = rotation;                               //更新方向变量值,PhoneWindowManager中的方向。
        mAltOrientation = altOrientation;
        mPolicy.setRotationLw(mRotation);

        mWindowsFreezingScreen = true;                   //冻结屏幕
        mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
        mH.sendEmptyMessageDelayed(H.WINDOW_FREEZE_TIMEOUT, WINDOW_FREEZE_TIMEOUT_DURATION);  //发送一个冻结超时消息,如果超时了还没解冻,那么这个消息的处理函数就会主动解冻屏幕。
        mWaitingForConfig = true;
        final DisplayContent displayContent = getDefaultDisplayContentLocked();
        displayContent.layoutNeeded = true;                     //屏幕旋转,那么必然需要重新layout;
        final int[] anim = new int[2];
        if (displayContent.isDimming()) {
            anim[0] = anim[1] = 0;
        } else {
            mPolicy.selectRotationAnimationLw(anim);           //选择一个旋转动画;
        }
        startFreezingDisplayLocked(inTransaction, anim[0], anim[1]);         //启动屏幕冻结;
        // startFreezingDisplayLocked can reset the ScreenRotationAnimation.
        screenRotationAnimation =
                mAnimator.getScreenRotationAnimationLocked(Display.DEFAULT_DISPLAY);

        // We need to update our screen size information to match the new
        // rotation.  Note that this is redundant with the later call to
        // sendNewConfiguration() that must be called after this function
        // returns...  however we need to do the screen size part of that
        // before then so we have the correct size to use when initializing
        // the rotation animation for the new rotation.
        computeScreenConfigurationLocked(null);

        final DisplayInfo displayInfo = displayContent.getDisplayInfo();
        if (!inTransaction) {
            if (SHOW_TRANSACTIONS) {
                Slog.i(TAG, ">>> OPEN TRANSACTION setRotationUnchecked");
            }
            SurfaceControl.openTransaction();
        }
        try {                                           //启动一次屏幕旋转动画;
            // NOTE: We disable the rotation in the emulator because
            //       it doesn't support hardware OpenGL emulation yet.
            if (CUSTOM_SCREEN_ROTATION && screenRotationAnimation != null
                    && screenRotationAnimation.hasScreenshot()) {
                if (screenRotationAnimation.setRotationInTransaction(
                        rotation, mFxSession,
                        MAX_ANIMATION_DURATION, mTransitionAnimationScale,
                        displayInfo.logicalWidth, displayInfo.logicalHeight)) {
                    scheduleAnimationLocked();
                }
                if (FeatureOption.MTK_SMARTBOOK_SUPPORT) {
                    screenRotationAnimation.setSnapshotScaleForSMB(displayInfo.rotation, displayContent.mBaseDisplayWidth, displayContent.mBaseDisplayHeight);
                }
            }

            mDisplayManagerService.performTraversalInTransactionFromWindowManager();
        } finally {
            if (!inTransaction) {
                SurfaceControl.closeTransaction();
                if (SHOW_LIGHT_TRANSACTIONS) {
                    Slog.i(TAG, "<<< CLOSE TRANSACTION setRotationUnchecked");
                }
            }
        }

        final WindowList windows = displayContent.getWindowList();
        for (int i = windows.size() - 1; i >= 0; i--) {
            WindowState w = windows.get(i);
            if (w.mHasSurface) {                         //对于未销毁surface的窗口,把mOrientationChanging设为true;
                if (DEBUG_ORIENTATION) Slog.v(TAG, "Set mOrientationChanging of " + w);
                w.mOrientationChanging = true;
                mInnerFields.mOrientationChangeComplete = false;
            }
            w.mLastFreezeDuration = 0;
        }

        for (int i=mRotationWatchers.size()-1; i>=0; i--) {      //回调注册了屏幕旋转监听器;
            try {
                mRotationWatchers.get(i).onRotationChanged(rotation);
            } catch (RemoteException e) {
            }
        }

        //TODO (multidisplay): Magnification is supported only for the default display.
        if (mDisplayMagnifier != null
                && displayContent.getDisplayId() == Display.DEFAULT_DISPLAY) {           //回调放大手势的屏幕旋转函数;
            mDisplayMagnifier.onRotationChangedLocked(getDefaultDisplayContentLocked(), rotation);
        }
        return true;
    }
3、performLayoutLockedInner()
 private final void performLayoutLockedInner(final DisplayContent displayContent,
                                    boolean initial, boolean updateInputWindows) {
        if (!displayContent.layoutNeeded) {   //如果需要relayout,那么必然先要把layoutNeeded值设为true;
            return;
        }
        displayContent.layoutNeeded = false;      //重置为false;   
        WindowList windows = displayContent.getWindowList();
        boolean isDefaultDisplay = displayContent.isDefaultDisplay;

        DisplayInfo displayInfo = displayContent.getDisplayInfo();
        final int dw = displayInfo.logicalWidth;
        final int dh = displayInfo.logicalHeight;

        final int NFW = mFakeWindows.size();
        for (int i=0; i<NFW; i++) {
            mFakeWindows.get(i).layout(dw, dh);
        }

        final int N = windows.size();
        int i;

        if (DEBUG_LAYOUT) {
            Slog.v(TAG, "-------------------------------------");
            Slog.v(TAG, "performLayout: needed="
                    + displayContent.layoutNeeded + " dw=" + dw + " dh=" + dh);
        }

        WindowStateAnimator universeBackground = null;

        mPolicy.beginLayoutLw(isDefaultDisplay, dw, dh, mRotation);  //调用PhoneWindowManager.beginLayoutLw()
        if (isDefaultDisplay) {
            // Not needed on non-default displays.
            mSystemDecorLayer = mPolicy.getSystemDecorLayerLw();
            mScreenRect.set(0, 0, dw, dh);
        }

        mPolicy.getContentRectLw(mTmpContentRect);
        displayContent.setStackBoxSize(mTmpContentRect);  //设置StackBox大小,可以缩放多窗口???
        int seq = mLayoutSeq+1;
        if (seq < 0) seq = 0;
        mLayoutSeq = seq;

        boolean behindDream = false;

        // First perform layout of any root windows (not attached
        // to another window).
        int topAttached = -1;
        for (i = N-1; i >= 0; i--) {
            final WindowState win = windows.get(i);           //只layout可见的窗口;

            // Don't do layout of a window if it is not visible, or
            // soon won't be visible, to avoid wasting time and funky
            // changes while a window is animating away.
            final boolean gone = (behindDream && mPolicy.canBeForceHidden(win, win.mAttrs))
                    || win.isGoneForLayoutLw();

            if (DEBUG_LAYOUT && !win.mLayoutAttached) {
                Slog.v(TAG, "1ST PASS " + win
                        + ": gone=" + gone + " mHaveFrame=" + win.mHaveFrame
                        + " mLayoutAttached=" + win.mLayoutAttached
                        + " screen changed=" + win.isConfigChanged());
                final AppWindowToken atoken = win.mAppToken;
                if (gone) Slog.v(TAG, "  GONE: mViewVisibility="
                        + win.mViewVisibility + " mRelayoutCalled="
                        + win.mRelayoutCalled + " hidden="
                        + win.mRootToken.hidden + " hiddenRequested="
                        + (atoken != null && atoken.hiddenRequested)
                        + " mAttachedHidden=" + win.mAttachedHidden);
                else Slog.v(TAG, "  VIS: mViewVisibility="
                        + win.mViewVisibility + " mRelayoutCalled="
                        + win.mRelayoutCalled + " hidden="
                        + win.mRootToken.hidden + " hiddenRequested="
                        + (atoken != null && atoken.hiddenRequested)
                        + " mAttachedHidden=" + win.mAttachedHidden);
            }

            // If this view is GONE, then skip it -- keep the current
            // frame, and let the caller know so they can ignore it
            // if they want.  (We do the normal layout for INVISIBLE
            // windows, since that means "perform layout as normal,
            // just don't display").
            if (!gone || !win.mHaveFrame || win.mLayoutNeeded
                    || ((win.isConfigChanged() || win.setInsetsChanged()) &&prepareAppTransition
                            (win.mAttrs.type == TYPE_KEYGUARD ||
                            win.mAppToken != null && win.mAppToken.layoutConfigChanges))
                    || win.mAttrs.type == TYPE_UNIVERSE_BACKGROUND) {
                if (!win.mLayoutAttached) {
                    if (initial) {
                        //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial");
                        win.mContentChanged = false;
                    }
                    if (win.mAttrs.type == TYPE_DREAM) {
                        // Don't layout windows behind a dream, so that if it
                        // does stuff like hide the status bar we won't get a
                        // bad transition when it goes away.
                        behindDream = true;
                    }
                    win.mLayoutNeeded = false;
                    win.prelayout();
                    mPolicy.layoutWindowLw(win, win.mAttrs, null);
                    win.mLayoutSeq = seq;
                    win.mLayoutOrientation = mCurConfiguration.orientation;
                    if (DEBUG_LAYOUT) Slog.v(TAG, "  LAYOUT: mFrame="
                            + win.mFrame + " mContainingFrame="
                            + win.mContainingFrame + " mDisplayFrame="
                            + win.mDisplayFrame);
                } else {
                    if (topAttached < 0) topAttached = i;
                }
            }
            if (win.mViewVisibility == View.VISIBLE
                    && win.mAttrs.type == TYPE_UNIVERSE_BACKGROUND
                    && universeBackground == null) {
                universeBackground = win.mWinAnimator;
            }
        }

        if (mAnimator.mUniverseBackground  != universeBackground) {
            mFocusMayChange = true;
            mAnimator.mUniverseBackground = universeBackground;
        }

        boolean attachedBehindDream = false;

        // Now perform layout of attached windows, which usually
        // depend on the position of the window they are attached to.
        // XXX does not deal with windows that are attached to windows
        // that are themselves attached.
        for (i = topAttached; i >= 0; i--) {
            final WindowState win = windows.get(i);

            if (win.mLayoutAttached) {
                if (DEBUG_LAYOUT) Slog.v(TAG, "2ND PASS " + win
                        + " mHaveFrame=" + win.mHaveFrame
                        + " mViewVisibility=" + win.mViewVisibility
                        + " mRelayoutCalled=" + win.mRelayoutCalled);
                // If this view is GONE, then skip it -- keep the current
                // frame, and let the caller know so they can ignore it
                // if they want.  (We do the normal layout for INVISIBLE
                // windows, since that means "perform layout as normal,
                // just don't display").
                if (attachedBehindDream && mPolicy.canBeForceHidden(win, win.mAttrs)) {
                    continue;
                }
                if ((win.mViewVisibility != View.GONE && win.mRelayoutCalled)
                        || !win.mHaveFrame || win.mLayoutNeeded) {
                    if (initial) {
                        //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial");
                        win.mContentChanged = false;
                    }
                    win.mLayoutNeeded = false;
                    win.prelayout();
                    mPolicy.layoutWindowLw(win, win.mAttrs, win.mAttachedWindow);
                    win.mLayoutSeq = seq;
                    win.mLayoutOrientation = mCurConfiguration.orientation;
                    if (DEBUG_LAYOUT) Slog.v(TAG, "  LAYOUT: mFrame="
                            + win.mFrame + " mContainingFrame="
                            + win.mContainingFrame + " mDisplayFrame="
                            + win.mDisplayFrame);
                }
            } else if (win.mAttrs.type == TYPE_DREAM) {
                // Don't layout windows behind a dream, so that if it
                // does stuff like hide the status bar we won't get a
                // bad transition when it goes away.
                attachedBehindDream = behindDream;
            }
        }

        // Window frames may have changed.  Tell the input dispatcher about it.
        mInputMonitor.setUpdateInputWindowsNeededLw();
        if (updateInputWindows) {
            mInputMonitor.updateInputWindowsLw(false /*force*/);
        }
        mPolicy.finishLayoutLw();
    }

4、performLayoutAndPlaceSurfacesLocked()函数

这个函数在很多地方调用,如果前一次调用完成了,那么后一次调用必然可以正常执行;如果前一次未执行完,直接调用performLayoutAndPlaceSurfacesLocked()时,结合performLayoutAndPlaceSurfacesLockedInner()中根据mInLayout值直接返回可以知道,此次调用实际上无效;

5、performLayoutAndPlaceSurfacesLockedInner()函数分析:

  private final void performLayoutAndPlaceSurfacesLockedInner(boolean recoveringMemory) {
        if (DEBUG_WINDOW_TRACE) {
            Slog.v(TAG, "performLayoutAndPlaceSurfacesLockedInner: entry. Called by "
                    + Debug.getCallers(3));
        }

        final long currentTime = SystemClock.uptimeMillis();

        int i;

        if (mFocusMayChange) {
            mFocusMayChange = false;
            updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
                    false /*updateInputWindows*/);
        }

        // Initialize state of exiting tokens.
        final int numDisplays = mDisplayContents.size();
        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
            final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
            for (i=displayContent.mExitingTokens.size()-1; i>=0; i--) {
                displayContent.mExitingTokens.get(i).hasVisible = false;
            }

            // Initialize state of exiting applications.
            for (i=displayContent.mExitingAppTokens.size()-1; i>=0; i--) {
                displayContent.mExitingAppTokens.get(i).hasVisible = false;
            }
        }

        mInnerFields.mHoldScreen = null;
        mInnerFields.mScreenBrightness = -1;
        mInnerFields.mButtonBrightness = -1;
        mInnerFields.mUserActivityTimeout = -1;
        mInnerFields.mObscureApplicationContentOnSecondaryDisplays = false;

        mTransactionSequence++;

        final DisplayContent defaultDisplay = getDefaultDisplayContentLocked();
        final DisplayInfo defaultInfo = defaultDisplay.getDisplayInfo();
        final int defaultDw = defaultInfo.logicalWidth;
        final int defaultDh = defaultInfo.logicalHeight;

        if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
                ">>> OPEN TRANSACTION performLayoutAndPlaceSurfaces");
        SurfaceControl.openTransaction();
        try {

            if (mWatermark != null) {
                mWatermark.positionSurface(defaultDw, defaultDh);
            }
            if (mStrictModeFlash != null) {
                mStrictModeFlash.positionSurface(defaultDw, defaultDh);
            }

            boolean focusDisplayed = false;

            for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
                final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
                boolean updateAllDrawn = false;
                WindowList windows = displayContent.getWindowList();
                DisplayInfo displayInfo = displayContent.getDisplayInfo();
                final int displayId = displayContent.getDisplayId();
                final int dw = displayInfo.logicalWidth;
                final int dh = displayInfo.logicalHeight;
                final int innerDw = displayInfo.appWidth;
                final int innerDh = displayInfo.appHeight;
                final boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY);

                // Reset for each display.
                mInnerFields.mDisplayHasContent = false;

                int repeats = 0;
                do {                    //①该循环最多调用7次,主要做了两件事,第一件是调用performLayoutLockedInner(),第二件是调用PhoneWindowManager的beginPostLayoutPolicyLw()、applyPostLayoutPolicyLw()、finishPostLayoutPolicyLw();
                    repeats++;
                    if (repeats > 6) {
                        Slog.w(TAG, "Animation repeat aborted after too many iterations");
                        displayContent.layoutNeeded = false;
                        break;
                    }

                    if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("On entry to LockedInner",
                        displayContent.pendingLayoutChanges);

                    if ((displayContent.pendingLayoutChanges &
                            WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER) != 0 &&
                            (adjustWallpaperWindowsLocked() &
                                    ADJUST_WALLPAPER_LAYERS_CHANGED) != 0) {
                        assignLayersLocked(windows);
                        displayContent.layoutNeeded = true;
                    }

                    if (isDefaultDisplay && (displayContent.pendingLayoutChanges
                            & WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG) != 0) {
                        if (DEBUG_LAYOUT) Slog.v(TAG, "Computing new config from layout");
                        if (updateOrientationFromAppTokensLocked(true)) {
                            displayContent.layoutNeeded = true;
                            mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
                        }
                    }

                    if ((displayContent.pendingLayoutChanges
                            & WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT) != 0) {
                        displayContent.layoutNeeded = true;
                    }

                    // FIRST LOOP: Perform a layout, if needed.
                    if (repeats < 4) {
                        performLayoutLockedInner(displayContent, repeats == 1,     /③performLayoutLockedInner()函数会调用PhoneWindowManager的beginLayoutLw()、layoutWindowLw()、finishLayoutLw()对root windows和attached windows分别进行layout;(1)beginLayoutLw()主要计算StatusBar和NavigationBar的Frame;(2)layoutWindowLw()就是计算出每个窗口的 parentFrame, displayFrame,overlayFrame, contentFrame, visibleFrame, decorFrame,然后再调用computeFrameLw()计算出真正的WindowState.mFrame、mContentInsets、mVisibleInsets、mCompatFrame等值;(3)finishLayoutLw()主要处理是否显示NavigationBar。
                                false /*updateInputWindows*/);
                    } else {
                        Slog.w(TAG, "Layout repeat skipped after too many iterations");
                    }

                    // FIRST AND ONE HALF LOOP: Make WindowManagerPolicy think
                    // it is animating.
                    displayContent.pendingLayoutChanges = 0;

                    if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("loop number "
                            + mLayoutRepeatCount, displayContent.pendingLayoutChanges);

                    if (isDefaultDisplay) {
                        mPolicy.beginPostLayoutPolicyLw(dw, dh);              //④调用PhoneWindowManager的beginPostLayoutPolicyLw(),该函数初始化一些变量如mTopFullscreenOpaqueWindowState、mForcingShowNavBar、mShowingLockscreen等等;
                        for (i = windows.size() - 1; i >= 0; i--) {
                            WindowState w = windows.get(i);
                            if (w.mHasSurface) {
                                mPolicy.applyPostLayoutPolicyLw(w, w.mAttrs);  //⑤调用PhoneWindowManager的applyPostLayoutPolicyLw(),该函数根据每个窗口WindowState及WindowManager.LayoutParams设定mTopFullscreenOpaqueWindowState、mForcingShowNavBar、mShowingLockscreen等值;
                            }
                        }
                        displayContent.pendingLayoutChanges |= mPolicy.finishPostLayoutPolicyLw();    //⑥调用PhoneWindowManager的finishPostLayoutPolicyLw(),该函数根据上一步求出来的mTopFullscreenOpaqueWindowState、mForcingShowNavBar、mShowingLockscreen等值,做出相应的操作,比如对状态栏和keyguard的显示隐藏等;当状态栏和keyguard显示或隐藏后,自然又需要重新layout,即重新循环③④⑤⑥;
                        if (mCurrentFocus != null) {
                            applyDarkStatusBarTheme(mCurrentFocus);
                        }                      
                        
                        if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats(
                            "after finishPostLayoutPolicyLw", displayContent.pendingLayoutChanges);
                    }
                } while (displayContent.pendingLayoutChanges != 0);

                mInnerFields.mObscured = false;
                mInnerFields.mSyswin = false;
                displayContent.resetDimming();

                // Only used if default window
                final boolean someoneLosingFocus = !mLosingFocus.isEmpty();

                final int N = windows.size();
                for (i=N-1; i>=0; i--) {                 //⑥对所有窗口WindowState进行for循环。主要处理壁纸显示、指定content frame chang动画(输入法弹出等动画)、计算并设置窗口Surface、收集frame和config更改的window方便后续告诉这些窗口有更新;
                    WindowState w = windows.get(i);

                    final boolean obscuredChanged = w.mObscured != mInnerFields.mObscured;

                    // Update effect.
                    w.mObscured = mInnerFields.mObscured;
                    if (!mInnerFields.mObscured) {
                        handleNotObscuredLocked(w, currentTime, innerDw, innerDh);
                    }

                    if (!w.getStack().testDimmingTag()) {
                        handleFlagDimBehind(w, innerDw, innerDh);
                    }

                    if (isDefaultDisplay && obscuredChanged && (mWallpaperTarget == w)  //⑥针对壁纸目标窗口重新设置壁纸可见性;
                            && w.isVisibleLw()) {
                        // This is the wallpaper target and its obscured state
                        // changed... make sure the current wallaper's visibility
                        // has been updated accordingly.
                        updateWallpaperVisibilityLocked();      
                    }

                    final WindowStateAnimator winAnimator = w.mWinAnimator;

                    // If the window has moved due to its containing
                    // content frame changing, then we'd like to animate
                    // it.
                    if (w.mHasSurface && w.shouldAnimateMove()) {              //⑥指定content frame chang动画(输入法弹出等动画);

                        // Frame has moved, containing content frame
                        // has also moved, and we're not currently animating...
                        // let's do something.
                        Animation a = AnimationUtils.loadAnimation(mContext,
                                com.android.internal.R.anim.window_move_from_decor);
                        winAnimator.setAnimation(a);
                        winAnimator.mAnimDw = w.mLastFrame.left - w.mFrame.left;
                        winAnimator.mAnimDh = w.mLastFrame.top - w.mFrame.top;
                        try {
                            w.mClient.moved(w.mFrame.left, w.mFrame.top);
                        } catch (RemoteException e) {
                        }
                    }

                    //Slog.i(TAG, "Window " + this + " clearing mContentChanged - done placing");
                    w.mContentChanged = false;

                    // Moved from updateWindowsAndWallpaperLocked().
                    if (w.mHasSurface) {
                        // Take care of the window being ready to display.
                        final boolean committed =
                                winAnimator.commitFinishDrawingLocked(currentTime);
                        if (isDefaultDisplay && committed) {
                            if (w.mAttrs.type == TYPE_DREAM) {
                                // HACK: When a dream is shown, it may at that
                                // point hide the lock screen.  So we need to
                                // redo the layout to let the phone window manager
                                // make this happen.
                                displayContent.pendingLayoutChanges |=
                                        WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
                                if (DEBUG_LAYOUT_REPEATS) {
                                    debugLayoutRepeats(
                                        "dream and commitFinishDrawingLocked true",
                                        displayContent.pendingLayoutChanges);
                                }
                            }
                            if ((w.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0) {        //⑥如果窗口属性设置了 FLAG_SHOW_WALLPAPER,那么将pendingLayoutChanges 增加FINISH_LAYOUT_REDO_WALLPAPER值,这样下次调用performLayoutAndPlaceSurfacesLockedInner时便能调用adjustWallpaperWindowsLocked()和assignLayersLocked()将壁纸窗口调整到合适位置;                                                                                                                                       
                     if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
                                        "First draw done in potential wallpaper target " + w);
                                mInnerFields.mWallpaperMayChange = true;
                                displayContent.pendingLayoutChanges |=
                                        WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
                                if (DEBUG_LAYOUT_REPEATS) {
                                    debugLayoutRepeats(
                                        "wallpaper and commitFinishDrawingLocked true",
                                        displayContent.pendingLayoutChanges);
                                }
                            }
                        }

                        winAnimator.setSurfaceBoundariesLocked(recoveringMemory);     //⑥在第①条中的while循环已经重新计算了窗口的frame等大小,此函数便根据这些计算和的frame重新设置surface、WindowCrop等大小到SurfaceFlinger中;

                        final AppWindowToken atoken = w.mAppToken;
                        if (DEBUG_STARTING_WINDOW && atoken != null
                                && w == atoken.startingWindow) {
                            Slog.d(TAG, "updateWindows: starting " + w + " isOnScreen="
                                + w.isOnScreen() + " allDrawn=" + atoken.allDrawn
                                + " freezingScreen=" + atoken.mAppAnimator.freezingScreen);
                        }
                        if (atoken != null
                                && (!atoken.allDrawn || atoken.mAppAnimator.freezingScreen)) {
                            if (atoken.lastTransactionSequence != mTransactionSequence) {
                                atoken.lastTransactionSequence = mTransactionSequence;
                                atoken.numInterestingWindows = atoken.numDrawnWindows = 0;
                                atoken.startingDisplayed = false;
                            }
                            if ((w.isOnScreen() || winAnimator.mAttrType == TYPE_BASE_APPLICATION)
                                    && !w.mExiting && !w.mDestroying) {
                                if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) {
                                    Slog.v(TAG, "Eval win " + w + ": isDrawn=" + w.isDrawnLw()
                                            + ", isAnimating=" + winAnimator.isAnimating());
                                    if (!w.isDrawnLw()) {
                                        Slog.v(TAG, "Not displayed: s=" + winAnimator.mSurfaceControl
                                                + " pv=" + w.mPolicyVisibility
                                                + " mDrawState=" + winAnimator.mDrawState
                                                + " ah=" + w.mAttachedHidden
                                                + " th=" + atoken.hiddenRequested
                                                + " a=" + winAnimator.mAnimating);
                                    }
                                }
                                if (w != atoken.startingWindow) {
                                    if (!atoken.mAppAnimator.freezingScreen || !w.mAppFreezing) {
                                        atoken.numInterestingWindows++;
                                        if (w.isDrawnLw()) {
                                            atoken.numDrawnWindows++;
                                            if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) Slog.v(TAG,
                                                    "tokenMayBeDrawn: " + atoken
                                                    + " freezingScreen=" + atoken.mAppAnimator.freezingScreen
                                                    + " mAppFreezing=" + w.mAppFreezing);
                                            updateAllDrawn = true;
                                        }
                                    }
                                } else if (w.isDrawnLw()) {
                                    atoken.startingDisplayed = true;
                                }
                            }
                        }
                    }

                    if (isDefaultDisplay && someoneLosingFocus && (w == mCurrentFocus)
                            && w.isDisplayedLw()) {
                        focusDisplayed = true;
                    }

                    updateResizingWindows(w);                      //⑥收集Frame、config更改的窗口,方便后面调用 client.resized()告诉上层应用窗口做出相应的调整;
                }

                mDisplayManagerService.setDisplayHasContent(displayId,
                        mInnerFields.mDisplayHasContent,
                        true /* inTraversal, must call performTraversalInTrans... below */);

                getDisplayContentLocked(displayId).stopDimmingIfNeeded();

                if (updateAllDrawn) {
                    updateAllDrawnLocked(displayContent);
                }
            }

            if (focusDisplayed) {
                mH.sendEmptyMessage(H.REPORT_LOSING_FOCUS);
            }

            // Give the display manager a chance to adjust properties
            // like display rotation if it needs to.
            mDisplayManagerService.performTraversalInTransactionFromWindowManager();

        } catch (RuntimeException e) {
            Log.wtf(TAG, "Unhandled exception in Window Manager", e);
        } finally {
            SurfaceControl.closeTransaction();
            if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
                    "<<< CLOSE TRANSACTION performLayoutAndPlaceSurfaces");
        }

        final WindowList defaultWindows = defaultDisplay.getWindowList();

        // If we are ready to perform an app transition, check through
        // all of the app tokens to be shown and see if they are ready
        // to go.
        if (mAppTransition.isReady()) {                                                          //⑦准备Activity切换动画;
            defaultDisplay.pendingLayoutChanges |= handleAppTransitionReadyLocked(defaultWindows);
            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after handleAppTransitionReadyLocked",
                    defaultDisplay.pendingLayoutChanges);
        }

        if (!mAnimator.mAnimating && mAppTransition.isRunning()) {
            // We have finished the animation of an app transition.  To do
            // this, we have delayed a lot of operations like showing and
            // hiding apps, moving apps in Z-order, etc.  The app token list
            // reflects the correct Z-order, but the window list may now
            // be out of sync with it.  So here we will just rebuild the
            // entire app window list.  Fun!
            defaultDisplay.pendingLayoutChanges |= handleAnimatingStoppedAndTransitionLocked();
            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after handleAnimStopAndXitionLock",
                defaultDisplay.pendingLayoutChanges);
        }

        if (mInnerFields.mWallpaperForceHidingChanged && defaultDisplay.pendingLayoutChanges == 0
                && !mAppTransition.isReady()) {
            // At this point, there was a window with a wallpaper that
            // was force hiding other windows behind it, but now it
            // is going away.  This may be simple -- just animate
            // away the wallpaper and its window -- or it may be
            // hard -- the wallpaper now needs to be shown behind
            // something that was hidden.
            defaultDisplay.pendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after animateAwayWallpaperLocked",
                defaultDisplay.pendingLayoutChanges);
        }
        mInnerFields.mWallpaperForceHidingChanged = false;

        if (mInnerFields.mWallpaperMayChange) {
            if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "Wallpaper may change!  Adjusting");
            defaultDisplay.pendingLayoutChanges |=
                    WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("WallpaperMayChange",
                    defaultDisplay.pendingLayoutChanges);
        }

        if (mFocusMayChange) {         //⑦更新焦点窗口;
            mFocusMayChange = false;
            if (updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES,
                    false /*updateInputWindows*/)) {
                defaultDisplay.pendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
            }
        }

        if (needsLayout()) {          //⑦如果此时还需要layout,那么将pendingLayoutChanges添加FINISH_LAYOUT_REDO_LAYOUT,这样下次调用performLayoutAndPlaceSurfacesLockedInner()时便能重新layout;
            defaultDisplay.pendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("mLayoutNeeded",
                    defaultDisplay.pendingLayoutChanges);
        }

        for (i = mResizingWindows.size() - 1; i >= 0; i--) {           //⑧对于frame、config等有更改的window,调用client.resized()通知上层应用窗口;
            WindowState win = mResizingWindows.get(i);
            if (win.mAppFreezing) {
                // Don't remove this window until rotation has completed.
                continue;
            }
            final WindowStateAnimator winAnimator = win.mWinAnimator;
            try {
                if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG,
                        "Reporting new frame to " + win + ": " + win.mCompatFrame);
                int diff = 0;
                boolean configChanged = win.isConfigChanged();
                if ((DEBUG_RESIZE || DEBUG_ORIENTATION || DEBUG_CONFIGURATION)
                        && configChanged) {
                    Slog.i(TAG, "Sending new config to window " + win + ": "
                            + winAnimator.mSurfaceW + "x" + winAnimator.mSurfaceH
                            + " / " + mCurConfiguration + " / 0x"
                            + Integer.toHexString(diff));
                }
                win.setConfiguration(mCurConfiguration);
                if (DEBUG_ORIENTATION &&
                        winAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING) Slog.i(
                        TAG, "Resizing " + win + " WITH DRAW PENDING");
                final IWindow client = win.mClient;
                final Rect frame = win.mFrame;
                final Rect overscanInsets = win.mLastOverscanInsets;
                final Rect contentInsets = win.mLastContentInsets;
                final Rect visibleInsets = win.mLastVisibleInsets;
                final boolean reportDraw
                        = winAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING;
                final Configuration newConfig = configChanged ? win.mConfiguration : null;
                if (win.mClient instanceof IWindow.Stub) {
                    // To prevent deadlock simulate one-way call if win.mClient is a local object.
                    mH.post(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                client.resized(frame, overscanInsets, contentInsets,
                                        visibleInsets, reportDraw, newConfig);
                            } catch (RemoteException e) {
                                // Not a remote call, RemoteException won't be raised.
                            }
                        }
                    });
                } else {
                   client.resized(frame, overscanInsets, contentInsets, visibleInsets, reportDraw,
                           newConfig);
                }
                win.mOverscanInsetsChanged = false;
                win.mContentInsetsChanged = false;
                win.mVisibleInsetsChanged = false;
                winAnimator.mSurfaceResized = false;
            } catch (RemoteException e) {
                win.mOrientationChanging = false;
                win.mLastFreezeDuration = (int)(SystemClock.elapsedRealtime()
                        - mDisplayFreezeTime);
            }
            mResizingWindows.remove(i);
        }

        if (DEBUG_ORIENTATION && mDisplayFrozen) Slog.v(TAG,
                "With display frozen, orientationChangeComplete="
                + mInnerFields.mOrientationChangeComplete);
        if (mInnerFields.mOrientationChangeComplete) {    //⑧如果转屏操作完成,那么就将屏幕解冻;
            if (mWindowsFreezingScreen) {
                mWindowsFreezingScreen = false;
                mLastFinishedFreezeSource = mInnerFields.mLastWindowFreezeSource;
                mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
            }
            stopFreezingDisplayLocked();
        }

        // Destroy the surface of any windows that are no longer visible.
        boolean wallpaperDestroyed = false;
        i = mDestroySurface.size();     //⑧销毁掉Surface;
        if (i > 0) {
            do {
                i--;
                WindowState win = mDestroySurface.get(i);
                win.mDestroying = false;
                if (mInputMethodWindow == win) {
                    mInputMethodWindow = null;
                }
                if (win == mWallpaperTarget) {
                    wallpaperDestroyed = true;
                }
                win.mWinAnimator.destroySurfaceLocked();
            } while (i > 0);
            mDestroySurface.clear();
        }

        // Time to remove any exiting tokens?
        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {     //⑧移除退出的WindowToken;
            final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
            ArrayList<WindowToken> exitingTokens = displayContent.mExitingTokens;
            for (i = exitingTokens.size() - 1; i >= 0; i--) {
                WindowToken token = exitingTokens.get(i);
                if (!token.hasVisible) {
                    exitingTokens.remove(i);
                    if (token.windowType == TYPE_WALLPAPER) {
                        mWallpaperTokens.remove(token);
                    }
                }
            }

            // Time to remove any exiting applications?
            AppTokenList exitingAppTokens = displayContent.mExitingAppTokens;
            for (i = exitingAppTokens.size() - 1; i >= 0; i--) {          //⑧移除掉退出的APPWindowToken;
                AppWindowToken token = exitingAppTokens.get(i);
                if (!token.hasVisible && !mClosingApps.contains(token)) {
                    // Make sure there is no animation running on this token,
                    // so any windows associated with it will be removed as
                    // soon as their animations are complete
                    token.mAppAnimator.clearAnimation();
                    token.mAppAnimator.animating = false;
                    
                    //FLYME BEGIN 锛沘ctionbar animation
                    if(token.mAppAnimator.mActionbarAnimator != null) {
                        token.mAppAnimator.mActionbarAnimator.destroy();
                        token.mAppAnimator.mActionbarAnimator = null;
                    }
                    
                    if(token.mAppAnimator.mSplitActionbarAnimator != null) {
                        token.mAppAnimator.mSplitActionbarAnimator.destroy();
                        token.mAppAnimator.mSplitActionbarAnimator = null;
                    }
                    //FLYME END
                    if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
                            "performLayout: App token exiting now removed" + token);
                    final Task task = mTaskIdToTask.get(token.groupId);
                    if (task != null && task.removeAppToken(token)) {
                        mTaskIdToTask.delete(token.groupId);
                    }
                    exitingAppTokens.remove(i);
                }
            }
        }

        if (!mAnimator.mAnimating && mRelayoutWhileAnimating.size() > 0) {
            for (int j=mRelayoutWhileAnimating.size()-1; j>=0; j--) {
                try {
                    mRelayoutWhileAnimating.get(j).mClient.doneAnimating();
                } catch (RemoteException e) {
                }
            }
            mRelayoutWhileAnimating.clear();
        }

        if (wallpaperDestroyed) {
            defaultDisplay.pendingLayoutChanges |=
                    WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
            defaultDisplay.layoutNeeded = true;
        }

        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
            final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
            if (displayContent.pendingLayoutChanges != 0) {
                displayContent.layoutNeeded = true;
            }
        }

        // Finally update all input windows now that the window changes have stabilized.
        mInputMonitor.updateInputWindowsLw(true /*force*/);             //⑧前面两步移除了退出的窗口,现在把整理好的窗口重新添加到InputDispatcher中;

        setHoldScreenLocked(mInnerFields.mHoldScreen);
        if (!mDisplayFrozen) {
            if (mInnerFields.mScreenBrightness < 0 || mInnerFields.mScreenBrightness > 1.0f) {
                mPowerManager.setScreenBrightnessOverrideFromWindowManager(-1);
            } else {
                mPowerManager.setScreenBrightnessOverrideFromWindowManager(
                        toBrightnessOverride(mInnerFields.mScreenBrightness));
            }
            if (mInnerFields.mButtonBrightness < 0 || mInnerFields.mButtonBrightness > 1.0f) {
                mPowerManager.setButtonBrightnessOverrideFromWindowManager(-1);
            } else {
                mPowerManager.setButtonBrightnessOverrideFromWindowManager(
                        toBrightnessOverride(mInnerFields.mButtonBrightness));
            }
            mPowerManager.setUserActivityTimeoutOverrideFromWindowManager(
                    mInnerFields.mUserActivityTimeout);
        }

        if (mTurnOnScreen) {
            if (DEBUG_VISIBILITY) Slog.v(TAG, "Turning screen on after layout!");
            mPowerManager.wakeUp(SystemClock.uptimeMillis());
            mTurnOnScreen = false;
        }

        if (mInnerFields.mUpdateRotation) {
            if (DEBUG_ORIENTATION) Slog.d(TAG, "Performing post-rotate rotation");
            if (updateRotationUncheckedLocked(false)) {
                mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
            } else {
                mInnerFields.mUpdateRotation = false;
            }
        }

        if (mInnerFields.mOrientationChangeComplete && !defaultDisplay.layoutNeeded
                && !mInnerFields.mUpdateRotation) {
            checkDrawnWindowsLocked();
        }

        final int N = mPendingRemove.size();       //⑨如果存在待移除的窗口,调用removeWindowInnerLocked()把这些窗口移除掉
        if (N > 0) {
            if (mPendingRemoveTmp.length < N) {
                mPendingRemoveTmp = new WindowState[N+10];
            }
            mPendingRemove.toArray(mPendingRemoveTmp);
            mPendingRemove.clear();
            DisplayContentList displayList = new DisplayContentList();
            for (i = 0; i < N; i++) {
                WindowState w = mPendingRemoveTmp[i];
                removeWindowInnerLocked(w.mSession, w);
                if (!displayList.contains(w.mDisplayContent)) {
                    displayList.add(w.mDisplayContent);
                }
            }

            for (DisplayContent displayContent : displayList) {
                assignLayersLocked(displayContent.getWindowList());         //⑨重新分配layer高度;
                displayContent.layoutNeeded = true;
            }
        }

        setFocusedStackFrame();                                    //⑨设置mFocusedStackFrame大小;

        // Check to see if we are now in a state where the screen should
        // be enabled, because the window obscured flags have changed.
        enableScreenIfNeededLocked();

        scheduleAnimationLocked();                             //⑨启动播放动画;

        if (DEBUG_WINDOW_TRACE) {
            Slog.e(TAG, "performLayoutAndPlaceSurfacesLockedInner exit: animating="
                    + mAnimator.mAnimating);
        }
    }

总结:该函数主要干了三件事,第一是layout窗口,调用performLayoutLockedInner()计算窗口大小,再调用PhoneWindowManager的beginPostLayoutPolicyLw()、applyPostLayoutPolicyLw()、finishPostLayoutPolicyLw()更新状态栏和keyguard的状态,有可能又重新循环调用这几个函数;第二,更新窗口的surface、WindowCrop等大小到SurfaceFlinger中,更新壁纸的窗口位置和显示;通知上层应用窗口大小及config的更改;第三,移除掉不必要的窗口,并把窗口list更新到InputDispatcher中;同时重新分配窗口Layer的高度;

6、addWindow()

    public int addWindow(Session session, IWindow client, int seq,
            WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
            Rect outContentInsets, InputChannel outInputChannel) {
        int[] appOp = new int[1];
        int res = mPolicy.checkAddPermission(attrs, appOp);
        if (res != WindowManagerGlobal.ADD_OKAY) {
            return res;
        }

        boolean reportNewConfig = false;
        WindowState attachedWindow = null;
        WindowState win = null;
        long origId;
        final int type = attrs.type;

        synchronized(mWindowMap) {
            if (!mDisplayReady) {
                throw new IllegalStateException("Display has not been initialialized");
            }

            final DisplayContent displayContent = getDisplayContentLocked(displayId);
            if (displayContent == null) {
                Slog.w(TAG, "Attempted to add window to a display that does not exist: "
                        + displayId + ".  Aborting.");
                return WindowManagerGlobal.ADD_INVALID_DISPLAY;
            }
            if (!displayContent.hasAccess(session.mUid)) {
                Slog.w(TAG, "Attempted to add window to a display for which the application "
                        + "does not have access: " + displayId + ".  Aborting.");
                return WindowManagerGlobal.ADD_INVALID_DISPLAY;
            }

            if (mWindowMap.containsKey(client.asBinder())) {
                Slog.w(TAG, "Window " + client + " is already added");
                return WindowManagerGlobal.ADD_DUPLICATE_ADD;
            }

            if (type >= FIRST_SUB_WINDOW && type <= LAST_SUB_WINDOW) {    //①如果add的是子窗口,如popwindow,那么先根据token找到父窗口attachedWindow,还会判断父窗口attachedWindow是否也是子窗口类型,如果也是子窗口那么添加不成功;
                attachedWindow = windowForClientLocked(null, attrs.token, false);
                if (attachedWindow == null) {
                    Slog.w(TAG, "Attempted to add window with token that is not a window: "
                          + attrs.token + ".  Aborting.");
                    return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;
                }
                if (attachedWindow.mAttrs.type >= FIRST_SUB_WINDOW
                        && attachedWindow.mAttrs.type <= LAST_SUB_WINDOW) {
                    Slog.w(TAG, "Attempted to add window with token that is a sub-window: "
                            + attrs.token + ".  Aborting.");
                    return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;
                }
            }

            if (type == TYPE_PRIVATE_PRESENTATION && !displayContent.isPrivate()) {
                Slog.w(TAG, "Attempted to add private presentation window to a non-private display.  Aborting.");
                return WindowManagerGlobal.ADD_PERMISSION_DENIED;
            }

            boolean addToken = false;
            WindowToken token = mTokenMap.get(attrs.token);      //②mTokenMap中保存着所有的WindowToken和APPWindowToken, 如果add子窗口,那么get的WindowToken不应该为null呀,但是add PopupWindow子窗口时确实为null,不知道为什么?下面的逻辑是如果add 普通Activity窗口、输入法、壁纸、流窗口时,必须在之前已经添加了WindowToken时才行;所以对于PopupWindow,会new 一个WindowToken;好奇怪,子窗口怎么还会new一个WindowToken;
            if (token == null) {
                if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
                    Slog.w(TAG, "Attempted to add application window with unknown token "
                          + attrs.token + ".  Aborting.");
                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                }
                if (type == TYPE_INPUT_METHOD) {
                    Slog.w(TAG, "Attempted to add input method window with unknown token "
                          + attrs.token + ".  Aborting.");
                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                }
                if (type == TYPE_WALLPAPER) {
                    Slog.w(TAG, "Attempted to add wallpaper window with unknown token "
                          + attrs.token + ".  Aborting.");
                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                }
                if (type == TYPE_DREAM) {
                    Slog.w(TAG, "Attempted to add Dream window with unknown token "
                          + attrs.token + ".  Aborting.");
                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                }
                token = new WindowToken(this, attrs.token, -1, false);
                addToken = true;
            } else if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
                AppWindowToken atoken = token.appWindowToken;
                if (atoken == null) {
                    Slog.w(TAG, "Attempted to add window with non-application token "
                          + token + ".  Aborting.");
                    return WindowManagerGlobal.ADD_NOT_APP_TOKEN;
                } else if (atoken.removed) {
                    Slog.w(TAG, "Attempted to add window with exiting application token "
                          + token + ".  Aborting.");
                    return WindowManagerGlobal.ADD_APP_EXITING;
                }
                if (type == TYPE_APPLICATION_STARTING && atoken.firstWindowDrawn) {
                    // No need for this guy!
                    if (localLOGV) Slog.v(
                            TAG, "**** NO NEED TO START: " + attrs.getTitle());
                    return WindowManagerGlobal.ADD_STARTING_NOT_NEEDED;
                }
            } else if (type == TYPE_INPUT_METHOD) {
                if (token.windowType != TYPE_INPUT_METHOD) {
                    Slog.w(TAG, "Attempted to add input method window with bad token "
                            + attrs.token + ".  Aborting.");
                      return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                }
            } else if (type == TYPE_WALLPAPER) {
                if (token.windowType != TYPE_WALLPAPER) {
                    Slog.w(TAG, "Attempted to add wallpaper window with bad token "
                            + attrs.token + ".  Aborting.");
                      return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                }
            } else if (type == TYPE_DREAM) {
                if (token.windowType != TYPE_DREAM) {
                    Slog.w(TAG, "Attempted to add Dream window with bad token "
                            + attrs.token + ".  Aborting.");
                      return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                }
            }

            win = new WindowState(this, session, client, token,
                    attachedWindow, appOp[0], seq, attrs, viewVisibility, displayContent);   //③add的每个窗口都会new WindowState,该WindowState属于哪个WindowToken,父窗口是谁都从参数中穿进去;
            if (win.mDeathRecipient == null) {
                // Client has apparently died, so there is no reason to
                // continue.
                Slog.w(TAG, "Adding window client " + client.asBinder()
                        + " that is dead, aborting.");
                return WindowManagerGlobal.ADD_APP_EXITING;
            }

            mPolicy.adjustWindowParamsLw(win.mAttrs);
            win.setShowToOwnerOnlyLocked(mPolicy.checkShowToOwnerOnly(attrs));

            res = mPolicy.prepareAddWindowLw(win, attrs);              //④预处理addWindow,这个函数就是根据窗口类型做一些权限判断,如果是状态栏、导航栏则顺便赋值mStatusBar、mNavigationBar变量;
            if (res != WindowManagerGlobal.ADD_OKAY) {
                return res;
            }

            if (outInputChannel != null && (attrs.inputFeatures
                    & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {     //⑤为窗口新建一个输入通道到InputDispatcher中去,接受input消息;
                String name = win.makeInputChannelName();
                InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
                win.setInputChannel(inputChannels[0]);
                inputChannels[1].transferTo(outInputChannel);

                mInputManager.registerInputChannel(win.mInputChannel, win.mInputWindowHandle);
            }

            // From now on, no exceptions or errors allowed!

            res = WindowManagerGlobal.ADD_OKAY;

            origId = Binder.clearCallingIdentity();

            if (addToken) {
                mTokenMap.put(attrs.token, token);
            }
            win.attach();                                 //⑥attach()函数中会调用mSession.windowAddedLocked()—>new SurfaceSession(),每个进程都有一个Session对象,因此每个进程也会有一个SurfaceSession对象,该对象用于创建SurfaceControl;
 
 

            mWindowMap.put(client.asBinder(), win);       //⑦所有的窗口都在mWindowMap中有备份,方便通过client查找;
            if (win.mAppOp != AppOpsManager.OP_NONE) {
                if (mAppOps.startOpNoThrow(win.mAppOp, win.getOwningUid(), win.getOwningPackage())
                        != AppOpsManager.MODE_ALLOWED) {
                    win.setAppOpVisibilityLw(false);
                }
            }

            if (type == TYPE_APPLICATION_STARTING && token.appWindowToken != null) {    //⑦如果是启动窗口,那么将这个窗口保存在APPWindowToken.startingWindow中;
                token.appWindowToken.startingWindow = win;
                if (DEBUG_STARTING_WINDOW) Slog.v (TAG, "addWindow: " + token.appWindowToken
                        + " startingWindow=" + win);
                Message m = mH.obtainMessage(H.REMOVE_STARTING_TIMEOUT, token.appWindowToken);
                mH.sendMessageDelayed(m, STARTING_WINDOW_TIMEOUT_DURATION);
            }

            boolean imMayMove = true;

            if (type == TYPE_INPUT_METHOD) {              //⑦添加输入法,调用addInputMethodWindowToListLocked()添加到合适的位置,这个下面会详细研究;
                win.mGivenInsetsPending = true;
                mInputMethodWindow = win;
                addInputMethodWindowToListLocked(win);
                imMayMove = false;
            } else if (type == TYPE_INPUT_METHOD_DIALOG) {
                mInputMethodDialogs.add(win);
                addWindowToListInOrderLocked(win, true);
                moveInputMethodDialogsLocked(findDesiredInputMethodWindowIndexLocked(true));
                imMayMove = false;
            } else {
                addWindowToListInOrderLocked(win, true);      //⑧将窗口添加到合适的位置上去,这个在下面第7条中将详细分析;
                if (type == TYPE_WALLPAPER) {
                    mLastWallpaperTimeoutTime = 0;
                    displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
                } else if ((attrs.flags&FLAG_SHOW_WALLPAPER) != 0) {
                    displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
                } else if (mWallpaperTarget != null
                        && mWallpaperTarget.mLayer >= win.mBaseLayer) {
                    // If there is currently a wallpaper being shown, and
                    // the base layer of the new window is below the current
                    // layer of the target window, then adjust the wallpaper.
                    // This is to avoid a new window being placed between the
                    // wallpaper and its target.
                    displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
                }
            }

            win.mWinAnimator.mEnterAnimationPending = true;

            if (displayContent.isDefaultDisplay) {
                mPolicy.getContentInsetHintLw(attrs, outContentInsets);
            } else {
                outContentInsets.setEmpty();
            }

            if (mInTouchMode) {
                res |= WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE;
            }
            if (win.mAppToken == null || !win.mAppToken.clientHidden) {
                res |= WindowManagerGlobal.ADD_FLAG_APP_VISIBLE;
            }

            mInputMonitor.setUpdateInputWindowsNeededLw();      //⑨设置mUpdateInputWindowsNeeded为true,只有该变量为true时才可更新窗口信息到InputDispatcher中,除非强制更新

            boolean focusChanged = false;
            if (win.canReceiveKeys()) {
                focusChanged = updateFocusedWindowLocked(UPDATE_FOCUS_WILL_ASSIGN_LAYERS,      //⑨更新Focused窗口,这个将在下面第8点将详细分析;
                        false /*updateInputWindows*/);
                if (focusChanged) {
                    imMayMove = false;
                }
            }

            if (imMayMove) {
                moveInputMethodWindowsIfNeededLocked(false);
            }

            assignLayersLocked(displayContent.getWindowList());             //⑨为所有窗口重新分配Z轴高度值
            // Don't do layout here, the window must call
            // relayout to be displayed, so we'll do it there.

            if (focusChanged) {
                finishUpdateFocusedWindowAfterAssignLayersLocked(false /*updateInputWindows*/);     //⑨如果焦点窗口更改,那么调用finishUpdateFocusedWindowAfterAssignLayersLocked()完成后续工作;
            }
            mInputMonitor.updateInputWindowsLw(false /*force*/);            //⑨更新窗口到InputDispatcher中去;

            if (localLOGV) Slog.v(
                TAG, "New client " + client.asBinder()
                + ": window=" + win);

            if (win.isVisibleOrAdding() && updateOrientationFromAppTokensLocked(false)) {
                reportNewConfig = true;
            }
        }

        if (reportNewConfig) {
            sendNewConfiguration();
        }

        Binder.restoreCallingIdentity(origId);

        return res;
    }

总结:addWindow()函数主要做了件事:一、为窗口new WindowState,并加入到对应的WindowToken中去,并为窗口创建InputChannel;二、将窗口添加到窗口列表的合适位置去;三、重新分配窗口Z轴高度值,即重新计算Focus Window,并把窗口信息更新到InputDispatcher中去;

7、addWindowToListInOrderLocked()

    private void addWindowToListInOrderLocked(final WindowState win, boolean addToToken) {
        if (DEBUG_FOCUS_LIGHT) Slog.d(TAG, "addWindowToListInOrderLocked: win=" + win +
                " Callers=" + Debug.getCallers(4));
        if (win.mAttachedWindow == null) {
            final WindowToken token = win.mToken;
            int tokenWindowsPos = 0;
            if (token.appWindowToken != null) {
                tokenWindowsPos = addAppWindowToListLocked(win);
            } else {
                addFreeWindowToListLocked(win);
            }
            if (addToToken) {
                if (DEBUG_ADD_REMOVE) Slog.v(TAG, "Adding " + win + " to " + token);
                token.windows.add(tokenWindowsPos, win);
            }
        } else {
            addAttachedWindowToListLocked(win, addToToken);
        }

        if (win.mAppToken != null && addToToken) {
            win.mAppToken.allAppWindows.add(win);
        }
    }

总结:上述函数是添加一个窗口到窗口列表。如果window是子窗口,那么调用addAttachedWindowToListLocked(),如果是Activity窗口,那么调用addAppWindowToListLocked(),否则调用addFreeWindowToListLocked(),这三个函数下面进行详细分析。

(1)、addAppWindowToListLocked()

    private int addAppWindowToListLocked(final WindowState win) {
        final IWindow client = win.mClient;
        final WindowToken token = win.mToken;
        final DisplayContent displayContent = win.mDisplayContent;

        final WindowList windows = win.getWindowList();
        final int N = windows.size();
        WindowList tokenWindowList = getTokenWindowsOnDisplay(token, displayContent);
        int tokenWindowsPos = 0;
        int windowListPos = tokenWindowList.size();
        if (!tokenWindowList.isEmpty()) {              //①添加的窗口所属的APPWindowToken已经包含一些窗口,因此只要把窗口添加到这些窗口的顶部即可。但是对于TYPE_BASE_APPLICATION类型窗口需要添加到该APPWindowToken的最底部,还要注意startingWindow要处在最顶部;
            // If this application has existing windows, we
            // simply place the new window on top of them... but
            // keep the starting window on top.
            if (win.mAttrs.type == TYPE_BASE_APPLICATION) {
                // Base windows go behind everything else.
                WindowState lowestWindow = tokenWindowList.get(0);
                placeWindowBefore(lowestWindow, win);
                tokenWindowsPos = indexOfWinInWindowList(lowestWindow, token.windows);
            } else {
                AppWindowToken atoken = win.mAppToken;
                WindowState lastWindow = tokenWindowList.get(windowListPos - 1);
                if (atoken != null && lastWindow == atoken.startingWindow) {
                    placeWindowBefore(lastWindow, win);
                    tokenWindowsPos = indexOfWinInWindowList(lastWindow, token.windows);
                } else {
                    int newIdx = findIdxBasedOnAppTokens(win);
                    //there is a window above this one associated with the same
                    //apptoken note that the window could be a floating window
                    //that was created later or a window at the top of the list of
                    //windows associated with this token.
                    if (DEBUG_FOCUS_LIGHT || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG,
                            "not Base app: Adding window " + win + " at " + (newIdx + 1) + " of " +
                            N);
                    windows.add(newIdx + 1, win);
                    if (newIdx < 0) {
                        // No window from token found on win's display.
                        tokenWindowsPos = 0;
                    } else {
                        tokenWindowsPos = indexOfWinInWindowList(
                                windows.get(newIdx), token.windows) + 1;
                    }
                    mWindowsChanged = true;
                }
            }
            return tokenWindowsPos;
        }
                                          //②下面的逻辑是添加的窗口所属的APPWindowToken暂时还没有包含窗口,也就是说所属的APPWindowToken是第一次添加窗口;下面的逻辑就是找到窗口所属的APPWindowToken所处的位置,然后把WindowState加到对应位置;
        // No windows from this token on this display
        if (localLOGV) Slog.v(TAG, "Figuring out where to add app window " + client.asBinder()
                + " (token=" + token + ")");
        // Figure out where the window should go, based on the
        // order of applications.
        WindowState pos = null;

        final ArrayList<Task> tasks = displayContent.getTasks();
        int taskNdx;
        int tokenNdx = -1;
        for (taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {         //③这个循环找到taskNdx,tokenNdx,pos值,不是很好理解,分情况,在这把添加的窗口所属的APPWindowToken称为目标APPWindowToken。情况一、如果目标APPWindowToken所属的Task中目标APPWindowToken处于该Task的最底部,那么taskNdx指向目标APPWindowToken所属Task的前一个Task的位置,tokenNdx指向前一个Task中最后一个APPWindowToken的位置,这时只要把添加的窗口放到taskNdx指向的Task中tokenNdx指向的APPWindowToken中的所有窗口上面就好了。情况二、如果目标APPWindowToken所属的Task中目标APPWindowToken没有处于该Task的最底部,那么taskNdx指向目标APPWindowToken所属Task,tokenNdx指向所属Task中目标APPWindowToken的前一个APPWindowToken的位置,此时把添加窗口放到前一个APPWindowToken的所有窗口上面。情况一、二时,窗口添加动作由第⑤⑥组合起来完成。情况三、如果目标APPWindowToken所属的Task不是处于最顶部,那么这个循环后变量pos是指向目标APPWindowToken之后的APPWindowToken中最底部的窗口WindowState,此时需要把添加的窗口放到pos的前面即可,这个情况窗口添加动作由第④步完成。
            AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
            for (tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
                final AppWindowToken t = tokens.get(tokenNdx);
                if (t == token) {
                    --tokenNdx;
                    if (tokenNdx < 0) {
                        --taskNdx;
                        if (taskNdx >= 0) {
                            tokenNdx = tasks.get(taskNdx).mAppTokens.size() - 1;
                        }
                    }
                    break;
                }

                // We haven't reached the token yet; if this token
                // is not going to the bottom and has windows on this display, we can
                // use it as an anchor for when we do reach the token.
                tokenWindowList = getTokenWindowsOnDisplay(t, displayContent);
                if (!t.sendingToBottom && tokenWindowList.size() > 0) {
                    pos = tokenWindowList.get(0);
                }
            }
            if (tokenNdx >= 0) {
                // early exit
                break;
            }
        }

        // We now know the index into the apps.  If we found
        // an app window above, that gives us the position; else
        // we need to look some more.
        if (pos != null) {                             //④如果第③步中找到了pos,那么就用这个pos来确定窗口添加位置;
            // Move behind any windows attached to this one.
            WindowToken atoken = mTokenMap.get(pos.mClient.asBinder());
            if (atoken != null) {
                tokenWindowList =
                        getTokenWindowsOnDisplay(atoken, displayContent);
                final int NC = tokenWindowList.size();
                if (NC > 0) {
                    WindowState bottom = tokenWindowList.get(0);
                    if (bottom.mSubLayer < 0) {
                        pos = bottom;
                    }
                }
            }
            placeWindowBefore(pos, win);
            return tokenWindowsPos;
        }

        // Continue looking down until we find the first
        // token that has windows on this display.
        for ( ; taskNdx >= 0; --taskNdx) {               //⑤如果第③步中没找到pos,那么利用找到的taskNdx 和tokenNdx 来确定窗口添加位置;
            AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
            for ( ; tokenNdx >= 0; --tokenNdx) {
                final AppWindowToken t = tokens.get(tokenNdx);
                tokenWindowList = getTokenWindowsOnDisplay(t, displayContent);
                final int NW = tokenWindowList.size();
                if (NW > 0) {
                    pos = tokenWindowList.get(NW-1);
                    break;
                }
            }
            if (tokenNdx >= 0) {
                // found
                break;
            }
        }

        if (pos != null) {                                //⑥跟第⑤步配合完成添加窗口动作;
            // Move in front of any windows attached to this
            // one.
            WindowToken atoken = mTokenMap.get(pos.mClient.asBinder());
            if (atoken != null) {
                final int NC = atoken.windows.size();
                if (NC > 0) {
                    WindowState top = atoken.windows.get(NC-1);
                    if (top.mSubLayer >= 0) {
                        pos = top;
                    }
                }
            }
            placeWindowAfter(pos, win);
            return tokenWindowsPos;
        }

        // Just search for the start of this layer.
        final int myLayer = win.mBaseLayer;
        int i;
        for (i = 0; i < N; i++) {               //⑦这个逻辑基本不会走,为了防止前面六个步骤的遗漏情况补上的。根据mBaseLayer 值来确定添加位置;

            WindowState w = windows.get(i);
            if (w.mBaseLayer > myLayer) {
                break;
            }
        }
        if (DEBUG_FOCUS_LIGHT || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG,
                "Based on layer: Adding window " + win + " at " + i + " of " + N);
        windows.add(i, win);
        mWindowsChanged = true;
        return tokenWindowsPos;
    }

总结:添加一个窗口WindowState到Windows列表中有三种情况,都是为了代码执行效率才这么设计的。

(2)、addAttachedWindowToListLocked()

    private void addAttachedWindowToListLocked(final WindowState win, boolean addToToken) {
        final WindowToken token = win.mToken;
        final DisplayContent displayContent = win.mDisplayContent;
        final WindowState attached = win.mAttachedWindow;

        WindowList tokenWindowList = getTokenWindowsOnDisplay(token, displayContent);        //从属于token的窗口中筛选出与displayContent相同的窗口;

        // Figure out this window's ordering relative to the window
        // it is attached to.
        final int NA = tokenWindowList.size();
        final int sublayer = win.mSubLayer;
        int largestSublayer = Integer.MIN_VALUE;
        WindowState windowWithLargestSublayer = null;
        int i;
        for (i = 0; i < NA; i++) {                     //①该循环就是为了找一个合适的位置将子窗口插进入,注意是从最底部窗口开始循环的。
            WindowState w = tokenWindowList.get(i);
            final int wSublayer = w.mSubLayer;
            if (wSublayer >= largestSublayer) {         //②找到最顶部子窗口,看似下面会用到,如果这个for循环没有插入成功,那么便会走下面if(i>NA)逻辑;
                largestSublayer = wSublayer;
                windowWithLargestSublayer = w;
            }
            if (sublayer < 0) {                          //③如果添加的子窗口sublayer<0,那么只要从底部开始找到一个子窗口的sublayer大于要添加的子窗口sublayer值的窗口,并插入到找到窗口的前面即可,但是如果找到的子窗口位于BaseWindow的上面,那么便把子窗口插入到BaseWindow的前面即可。
                // For negative sublayers, we go below all windows
                // in the same sublayer.
                if (wSublayer >= sublayer) {
                    if (addToToken) {
                        if (DEBUG_ADD_REMOVE) Slog.v(TAG, "Adding " + win + " to " + token);
                        token.windows.add(i, win);
                    }
                    placeWindowBefore(wSublayer >= 0 ? attached : w, win);
                    break;
                }
            } else {               //④插入到比添加子窗口sublayer大的子窗口前面;
                // For positive sublayers, we go above all windows
                // in the same sublayer.
                if (wSublayer > sublayer) {
                    if (addToToken) {
                        if (DEBUG_ADD_REMOVE) Slog.v(TAG, "Adding " + win + " to " + token);
                        token.windows.add(i, win);
                    }
                    placeWindowBefore(w, win);
                    break;
                }
            }
        }
        if (i >= NA) {           //⑤如果③④中找不到比要添加的子窗口sublayer大的子窗口,那么就通过下面的逻辑来添加子窗口,如果sublayer小于0,那么就添加到attachWindow前面就好了,如果sublayer大于0,那么就添加到最大子窗口的上面,不存在子窗口的话自然添加到attachwindow的后面即可。
            if (addToToken) {
                if (DEBUG_ADD_REMOVE) Slog.v(TAG, "Adding " + win + " to " + token);
                token.windows.add(win);
            }
            if (sublayer < 0) {         
                placeWindowBefore(attached, win);
            } else {
                placeWindowAfter(largestSublayer >= 0
                                 ? windowWithLargestSublayer
                                 : attached,
                                 win);
            }
        }
    }

总结:从底部开始找到一个sublayer大于添加窗口sublayer值的子窗口,并添加在找到子窗口的前面,如果循环结束了还没找到到,那么自然就添加到窗口列表的顶部,这时还得分sublayer小于0和大于0的情况。

(3)、addFreeWindowToListLocked()

    private void addFreeWindowToListLocked(final WindowState win) {
        final WindowList windows = win.getWindowList();

        // Figure out where window should go, based on layer.
        final int myLayer = win.mBaseLayer;
        int i;
        for (i = windows.size() - 1; i >= 0; i--) {
            if (windows.get(i).mBaseLayer <= myLayer) {
                break;
            }
        }
        i++;
        if (DEBUG_FOCUS_LIGHT || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG,
                "Free window: Adding window " + win + " at " + i + " of " + windows.size());
        windows.add(i, win);
        mWindowsChanged = true;
    }

这个函数很简单,就是根据窗口的基本类型值mBaseLayer来添加,这个函数用于添加非Activity窗口。

8、updateFocusedWindowLocked()

    private boolean updateFocusedWindowLocked(int mode, boolean updateInputWindows) {
        WindowState newFocus = computeFocusedWindowLocked();                     //①计算出Focus window,computeFocusedWindowLocked()-->findFocusedWindowLocked(),findFocusedWindowLocked()函数在下面详细分析;
        if (mCurrentFocus != newFocus) {              //②如果计算出来的是new focus window,那么就做一些更新focus window操作;
            Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "wmUpdateFocus");
            // This check makes sure that we don't already have the focus
            // change message pending.
            mH.removeMessages(H.REPORT_FOCUS_CHANGE);
            mH.sendEmptyMessage(H.REPORT_FOCUS_CHANGE);
            // TODO(multidisplay): Focused windows on default display only.
            final DisplayContent displayContent = getDefaultDisplayContentLocked();
            final boolean imWindowChanged = moveInputMethodWindowsIfNeededLocked(
                    mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS
                            && mode != UPDATE_FOCUS_WILL_PLACE_SURFACES);
            if (imWindowChanged) {
                displayContent.layoutNeeded = true;
                newFocus = computeFocusedWindowLocked();
            }

            if (DEBUG_FOCUS_LIGHT || localLOGV) Slog.v(TAG, "Changing focus from " +
                    mCurrentFocus + " to " + newFocus + " Callers=" + Debug.getCallers(4));
            final WindowState oldFocus = mCurrentFocus;
            mCurrentFocus = newFocus;
            mLosingFocus.remove(newFocus);
            int focusChanged = mPolicy.focusChangedLw(oldFocus, newFocus);

            if (imWindowChanged && oldFocus != mInputMethodWindow) {
                // Focus of the input method window changed. Perform layout if needed.
                if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
                    performLayoutLockedInner(displayContent, true /*initial*/, updateInputWindows);
                    focusChanged &= ~WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
                } else if (mode == UPDATE_FOCUS_WILL_PLACE_SURFACES) {
                    // Client will do the layout, but we need to assign layers
                    // for handleNewWindowLocked() below.
                    assignLayersLocked(displayContent.getWindowList());
                }
            }

            if ((focusChanged & WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT) != 0) {
                // The change in focus caused us to need to do a layout.  Okay.
                displayContent.layoutNeeded = true;
                if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
                    performLayoutLockedInner(displayContent, true /*initial*/, updateInputWindows);
                }
            }

            if (mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS) {
                // If we defer assigning layers, then the caller is responsible for
                // doing this part.
                finishUpdateFocusedWindowAfterAssignLayersLocked(updateInputWindows);
            }

            Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
            return true;
        }
        return false;
    }

 findFocusedWindowLocked()

    private WindowState findFocusedWindowLocked(DisplayContent displayContent) {
        final WindowList windows = displayContent.getWindowList();
        for (int i = windows.size() - 1; i >= 0; i--) {
            final WindowState win = windows.get(i);

            if (localLOGV || DEBUG_FOCUS) Slog.v(
                TAG, "Looking for focus: " + i
                + " = " + win
                + ", flags=" + win.mAttrs.flags
                + ", canReceive=" + win.canReceiveKeys());

            AppWindowToken wtoken = win.mAppToken;

            // If this window's application has been removed, just skip it.
            if (wtoken != null && (wtoken.removed || wtoken.sendingToBottom)) {   //①如果该窗口所属的APPWindowToken已经从所属的Task中移除了(removeAppToken()),那么跳过该窗口;
                if (DEBUG_FOCUS) Slog.v(TAG, "Skipping " + wtoken + " because "
                        + (wtoken.removed ? "removed" : "sendingToBottom"));
                continue;
            }

            if (!win.canReceiveKeys()) {                               //②如果该窗口无法接受key事件,那么也跳过;什么时候才能接受key事件?必须可见(或窗口正在adding),必须没有设置FLAG_NOT_FOCUSABLE属性,如果设置了FLAG_NOT_FOCUSABLE属性,那么必然无法focus window;
                continue;
            }

            // Descend through all of the app tokens and find the first that either matches
            // win.mAppToken (return win) or mFocusedApp (return null).
            if (wtoken != null && win.mAttrs.type != TYPE_APPLICATION_STARTING &&
                    mFocusedApp != null) {
                ArrayList<Task> tasks = displayContent.getTasks();
                for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {   //③遍历所有Task中的APPWindowToken;
                    AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
                    int tokenNdx = tokens.size() - 1;
                    for ( ; tokenNdx >= 0; --tokenNdx) {
                        final AppWindowToken token = tokens.get(tokenNdx);
                        if (wtoken == token) {
                            break;
                        }
                        if (mFocusedApp == token) {
                            // Whoops, we are below the focused app...  no focus for you!
                            if (localLOGV || DEBUG_FOCUS_LIGHT) Slog.v(TAG,
                                    "findFocusedWindow: Reached focused app=" + mFocusedApp);
                            return null;
                        }
                    }
                    if (tokenNdx >= 0) {
                        // Early exit from loop, must have found the matching token.
                        break;
                    }
                }
            }

            if (DEBUG_FOCUS_LIGHT) Slog.v(TAG, "findFocusedWindow: Found new focus @ " + i +
                        " = " + win);
            return win;
        }

        if (DEBUG_FOCUS_LIGHT) Slog.v(TAG, "findFocusedWindow: No focusable windows.");
        return null;
    }
总结:整个找focus window的逻辑就是从顶部开始遍历窗口列表,其实最开始遍历的是那些非Activity窗口,如果那些窗口可以接受key事件,那么就把这个窗口作为focus窗口;如果非Activity窗口遍历完了,接着就是Activity窗口,对于Activity窗口,如果所属的APPWindowToken已经从Task中被移除了,那么也是要不能当focus window的;对于正在遍历的Activity窗口,如果其所属的APPWindowToken属于某个Task,并且不低于mFocusApp,那么该窗口就是focus window了;有个疑问,如果遍历的Activity窗口所属的APPWindowToken并没有保存在某个Task中,那么必然会遍历到mFocusApp之下,此时必然return null。在遍历到窗口列表的第一个Activity窗口时(此窗口可以获取key事件,可见),必然会return,一般情况下focus window就是这个Activity窗口了,如果第一个Activity窗口所属的APPWindowToken位于mFocusApp之下或没有添加到某个Task中,此时return null;WMS添加窗口的逻辑是先添加APPWindowToken,然后再addwindow,所以如果在已经添加了APPWindowToken但还没addwindow时,此状态也是return null;如果所有Activity窗口都无法接收key事件,那么也是return null;

9、rebuildAppWindowListLocked()

    private void rebuildAppWindowListLocked(final DisplayContent displayContent) {
        final WindowList windows = displayContent.getWindowList();
        int NW = windows.size();
        int i;
        int lastBelow = -1;
        int numRemoved = 0;

        if (mRebuildTmp.length < NW) {
            mRebuildTmp = new WindowState[NW+10];
        }

        // First remove all existing app windows.
        i=0;
        while (i < NW) {                  //①该循环结束后,i的值表示非Activity窗口的数量,numRemoved值表示Activity窗口WindowState数量;lastBelow值在壁纸窗口处在窗口列表的最底部时值为0,否认则值为-1;同时remove窗口时把win.mRebuilding设为true,这个变量在重新add进窗口列表时会设为false,对于没有add进来的窗口自然任然是true,在下面会根据窗口是否为true来找出那些lose窗口。
            if (w.mAppToken != null) {           
                WindowState win = windows.remove(i);
                win.mRebuilding = true;
                mRebuildTmp[numRemoved] = win;
                mWindowsChanged = true;
                if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Rebuild removing window: " + win);
                NW--;
                numRemoved++;
                continue;
            } else if (lastBelow == i-1) {
                if (w.mAttrs.type == TYPE_WALLPAPER || w.mAttrs.type == TYPE_UNIVERSE_BACKGROUND) {
                    lastBelow = i;
                }
            }
            i++;
        }

        // Keep whatever windows were below the app windows still below,
        // by skipping them.
        lastBelow++;                     //②加1后,lastBelow值在壁纸窗口处在窗口列表的最底部时值为1,否认则值为0;lastBelow的值赋给i;
        i = lastBelow;                                      

        // First add all of the exiting app tokens...  these are no longer
        // in the main app list, but still have windows shown.  We put them
        // in the back because now that the animation is over we no longer
        // will care about them.
        AppTokenList exitingAppTokens = displayContent.mExitingAppTokens;         //③这个循环把正在被remove的APPWindowToken的所有窗口通过调用reAddWindowLocked()挨个从0或1位置开始添加到窗口列表中;i的值表示前一个窗口被添加的位置+1,同时i值也表示已经被添加的窗口数量(lastBelow=1时,已经被添加的窗口数量=i-1)。i即可表示窗口位置值又表示添加的窗口数量,为什么?是因为对于Activity窗口来说BaseLayer值最低,都被挨个添加到窗口列表底部,不存在插入的窗口位置不连续的问题,所以下面会用i-=lastBelow求出总的添加的Activity窗口数量,然后跟第①步中移除的Activity窗口数量进行比较,相等当然是正常的,如果不相同那么自然有问题了;
        int NT = exitingAppTokens.size();
        for (int j=0; j<NT; j++) {
            i = reAddAppWindowsLocked(displayContent, i, exitingAppTokens.get(j));
        }

        // And add in the still active app tokens in Z order.
        final ArrayList<Task> tasks = displayContent.getTasks();       //④把Task中所有APPWindowToken中的窗口添加进去,添加逻辑跟第③条类似;注意此时是从Task列表的最底部开始添加;
        final int numTasks = tasks.size();
        for (int taskNdx = 0; taskNdx < numTasks; ++taskNdx) {
            final AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
            final int numTokens = tokens.size();
            for (int tokenNdx = 0; tokenNdx < numTokens; ++tokenNdx) {
                final AppWindowToken wtoken = tokens.get(tokenNdx);
                i = reAddAppWindowsLocked(displayContent, i, wtoken);
            }
        }

        i -= lastBelow;                                   //⑤在第③点中说了i - lastBelow等于重新add的Activity窗口数量;
        if (i != numRemoved) {                           //⑥如果不相同,那么说明有些Activity窗口没有add进来,是哪些窗口呢?WindowState.Rebuilding为true的窗口。从上面的添加逻辑可以知道对于这两种窗口需要被移除:1).APPWindowToken已经被移除,但WindowState还保存在窗口列表中;2).窗口WindowState已经从APPWindowToken中移除,但还没从窗口列表中移除;此时把这些lose窗口rebuild后不再保存在窗口列表中,那么自然要将窗口surface销毁掉;
            Slog.w(TAG, "Rebuild removed " + numRemoved + " windows but added " + i,
                    new RuntimeException("here").fillInStackTrace());
            for (i=0; i<numRemoved; i++) {
                WindowState ws = mRebuildTmp[i];
                if (ws.mRebuilding) {
                    StringWriter sw = new StringWriter();
                    PrintWriter pw = new FastPrintWriter(sw, false, 1024);
                    ws.dump(pw, "", true);
                    pw.flush();
                    Slog.w(TAG, "This window was lost: " + ws);
                    Slog.w(TAG, sw.toString());
                    ws.mWinAnimator.destroySurfaceLocked();
                }
            }
            Slog.w(TAG, "Current app token list:");
            dumpAppTokensLocked();
            Slog.w(TAG, "Final window list:");
            dumpWindowsLocked();
        }
    }

总结:rebuildAppWindowListLocked()函数分三步完成rebuild window逻辑,第一步是移除所有Activity窗口;第二步是添加正在被Remove的APPWindowToken的窗口;第三部是添加Task中的APPWindowToken中的窗口;设计思想是把属于APPWindowToken的窗口依次进行添加,这样就保证了属于同一个APPWindowToken的窗口总是聚在一起,中间不可能插入其他APPWindowToken的窗口,并且APPWindowToken的窗口是依据Task顺序来排布的,有可能出现有的窗口BaseLayer很高,但是排在BaseLayer很低的窗口之下。为什么要rebuild?首先自然是因为有的APPWindowToken正在退出,但还没被remove掉;其次是有可能窗口被add进来时就出现了窗口位置不正确的问题,此时刚好把他纠正过来;最后自然是清除一些APPWindowToken退出的窗口,及从APPWindowToken中移除的窗口;

也从中可以知道WMS中窗口的排列逻辑是:1).属于同一Activity的窗口相邻(同一APPWindowToken);2).Activity窗口按Task顺序排列;3).Activity窗口基本位于窗口列表底部;

10、removeWindowLocked()

    private void removeWindowLocked(Session session, WindowState win,
            boolean forceRemove) {
        if (win.mAttrs.type == TYPE_APPLICATION_STARTING) {
            if (DEBUG_STARTING_WINDOW) Slog.d(TAG, "Starting window removed " + win);
            removeStartingWindowTimeout(win.mAppToken);
        }

        if (localLOGV || DEBUG_FOCUS || DEBUG_FOCUS_LIGHT && win==mCurrentFocus) Slog.v(
                TAG, "Remove " + win + " client="
                + Integer.toHexString(System.identityHashCode(win.mClient.asBinder()))
                + ", surface=" + win.mWinAnimator.mSurfaceControl + " Callers="
                + Debug.getCallers(4));

        final long origId = Binder.clearCallingIdentity();

        win.disposeInputChannel();

        if (DEBUG_APP_TRANSITIONS) Slog.v(
                TAG, "Remove " + win + ": mSurface=" + win.mWinAnimator.mSurfaceControl
                + " mExiting=" + win.mExiting
                + " isAnimating=" + win.mWinAnimator.isAnimating()
                + " app-animation="
                + (win.mAppToken != null ? win.mAppToken.mAppAnimator.animation : null)
                + " inPendingTransaction="
                + (win.mAppToken != null ? win.mAppToken.inPendingTransaction : false)
                + " mDisplayFrozen=" + mDisplayFrozen);
        // Visibility of the removed window. Will be used later to update orientation later on.
        boolean wasVisible = false;
        // First, see if we need to run an animation.  If we do, we have
        // to hold off on removing the window until the animation is done.
        // If the display is frozen, just remove immediately, since the
        // animation wouldn't be seen.
        if (win.mHasSurface && okToDisplay()) {
            // If we are not currently running the exit animation, we
            // need to see about starting one.
            wasVisible = win.isWinVisibleLw();
            if (wasVisible) {

                int transit = WindowManagerPolicy.TRANSIT_EXIT;
                if (win.mAttrs.type == TYPE_APPLICATION_STARTING) {
                    transit = WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
                }
                // Try starting an animation.
                if (win.mWinAnimator.applyAnimationLocked(transit, false)) {
                    win.mExiting = true;
                }
                //TODO (multidisplay): Magnification is supported only for the default display.
                if (mDisplayMagnifier != null
                        && win.getDisplayId() == Display.DEFAULT_DISPLAY) {
                    mDisplayMagnifier.onWindowTransitionLocked(win, transit);
                }
            }
            if (!forceRemove && (win.mExiting || win.mWinAnimator.isAnimating())) {
                // The exit animation is running... wait for it!
                //Slog.i(TAG, "*** Running exit animation...");
                win.mExiting = true;
                win.mRemoveOnExit = true;
                win.mDisplayContent.layoutNeeded = true;
                updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
                        false /*updateInputWindows*/);
                performLayoutAndPlaceSurfacesLocked();
                if (win.mAppToken != null) {
                    win.mAppToken.updateReportedVisibilityLocked();
                }
                //dump();
                Binder.restoreCallingIdentity(origId);
                return;
            }
        }

        removeWindowInnerLocked(session, win);
        // Removing a visible window will effect the computed orientation
        // So just update orientation if needed.
        if (wasVisible && updateOrientationFromAppTokensLocked(false)) {
            mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
        }
        updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, true /*updateInputWindows*/);
        Binder.restoreCallingIdentity(origId);
    }

待续。

你可能感兴趣的:(WindowManagerService几个重要函数分析)