文章零散记录自己在学习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); }
待续。