android.view.WindowManagerGlobal#updateViewLayout
public void updateViewLayout(View view, ViewGroup.LayoutParams params) {if (view == null) {throw new IllegalArgumentException("view must not be null");}if (!(params instanceof WindowManager.LayoutParams)) {throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");}final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params;view.setLayoutParams(wparams);synchronized (mLock) {int index = findViewLocked(view, true);ViewRootImpl root = mRoots.get(index);mParams.remove(index);mParams.add(index, wparams);root.setLayoutParams(wparams, false);//1}
}
注释 1 处更新 ViewRootImpl 的 LayoutParams 属性
android.view.ViewRootImpl#setLayoutParams
public void setLayoutParams(WindowManager.LayoutParams attrs, boolean newView) {synchronized (this) {...if (newView) {mSoftInputMode = attrs.softInputMode;requestLayout();//1}...if (mWindowAttributes.softInputMode != oldSoftInputMode) {requestFitSystemWindows();//2}mWindowAttributesChanged = true;scheduleTraversals();//3}
}
注释 1、注释 2,都会执行 scheduleTraversals 方法(注释 3)
android.view.ViewRootImpl#scheduleTraversals
void scheduleTraversals() {if (!mTraversalScheduled) {mTraversalScheduled = true;mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();mChoreographer.postCallback(Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);//1notifyRendererOfFramePending();pokeDrawLockIfNeeded();}
}
mChoreographer 用于接收 VSync 信号,在下一帧被渲染时,调用 mTraversalRunnable 的 run 方法
android.view.ViewRootImpl.TraversalRunnable
final class TraversalRunnable implements Runnable {@Overridepublic void run() {doTraversal();}
}
android.view.ViewRootImpl#doTraversal
void doTraversal() {if (mTraversalScheduled) {mTraversalScheduled = false;mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);if (mProfile) {Debug.startMethodTracing("ViewAncestor");}performTraversals();//1if (mProfile) {Debug.stopMethodTracing();mProfile = false;}}
}
在注释 1 处开始 View 的绘制流程,即走 view 的 measure、layout、draw 三大步
android.view.ViewRootImpl#performTraversals
private void performTraversals() {...relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);//1...
}
在走 view 的 measure、layout、draw 三大步之前,会先调用 relayoutWindow
android.view.ViewRootImpl#relayoutWindow
private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,boolean insetsPending) throws RemoteException {float appScale = mAttachInfo.mApplicationScale;boolean restore = false;if (params != null && mTranslator != null) {restore = true;params.backup();mTranslator.translateWindowLayout(params);}if (params != null) {if (DBG) Log.d(mTag, "WindowLayout in layoutWindow:" + params);if (mOrigWindowType != params.type) {// For compatibility with old apps, don't crash here.if (mTargetSdkVersion < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {Slog.w(mTag, "Window type can not be changed after "+ "the window is added; ignoring change of " + mView);params.type = mOrigWindowType;}}}long frameNumber = -1;if (mSurface.isValid()) {frameNumber = mSurface.getNextFrameNumber();}int relayoutResult = mWindowSession.relayout(mWindow, params,(int) (mView.getMeasuredWidth() * appScale + 0.5f),(int) (mView.getMeasuredHeight() * appScale + 0.5f), viewVisibility,insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0, frameNumber,mTmpFrames, mPendingMergedConfiguration, mSurfaceControl, mTempInsets,mTempControls, mSurfaceSize);//1mPendingBackDropFrame.set(mTmpFrames.backdropFrame);if (mSurfaceControl.isValid()) {if (!useBLAST()) {mSurface.copyFrom(mSurfaceControl);} else {final Surface blastSurface = getOrCreateBLASTSurface();// If blastSurface == null that means it hasn't changed since the last time we// called. In this situation, avoid calling transferFrom as we would then// inc the generation ID and cause EGL resources to be recreated.if (blastSurface != null) {mSurface.transferFrom(blastSurface);}}if (mAttachInfo.mThreadedRenderer != null) {if (HardwareRenderer.isWebViewOverlaysEnabled()) {addPrepareSurfaceControlForWebviewCallback();addASurfaceTransactionCallback();}mAttachInfo.mThreadedRenderer.setSurfaceControl(mSurfaceControl);}} else {destroySurface();}mPendingAlwaysConsumeSystemBars =(relayoutResult & WindowManagerGlobal.RELAYOUT_RES_CONSUME_ALWAYS_SYSTEM_BARS) != 0;if (restore) {params.restore();}if (mTranslator != null) {mTranslator.translateRectInScreenToAppWindow(mTmpFrames.frame);mTranslator.translateInsetsStateInScreenToAppWindow(mTempInsets);mTranslator.translateSourceControlsInScreenToAppWindow(mTempControls);}setFrame(mTmpFrames.frame);//2mWillMove = false;mWillResize = false;mInsetsController.onStateChanged(mTempInsets);//3mInsetsController.onControlsChanged(mTempControls);//4return relayoutResult;
}
在注释 1 处,mWindowSession 是 IWindowSession 类型的字段,所以这里调用的是 IWindowSession::relayout 方法,IWindowSession 对应服务端的 com.android.server.wm.Session, 一个 ViewRootImpl 对应一个 Session,ViewRootImpl 与 WMS 的交互都要经由 Session 转发
IWindowSession 对应服务端的 com.android.server.wm.Session,所以注释 1 实际执行的是
com.android.server.wm.Session#relayout
@Override
public int relayout(IWindow window, WindowManager.LayoutParams attrs,int requestedWidth, int requestedHeight, int viewFlags, int flags, long frameNumber,ClientWindowFrames outFrames, MergedConfiguration mergedConfiguration,SurfaceControl outSurfaceControl, InsetsState outInsetsState,InsetsSourceControl[] outActiveControls, Point outSurfaceSize) {if (false) Slog.d(TAG_WM, ">>>>>> ENTERED relayout from "+ Binder.getCallingPid());Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, mRelayoutTag);int res = mService.relayoutWindow(this, window, attrs,requestedWidth, requestedHeight, viewFlags, flags, frameNumber,outFrames, mergedConfiguration, outSurfaceControl, outInsetsState,outActiveControls, outSurfaceSize);//1Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);if (false) Slog.d(TAG_WM, "<<<<<< EXITING relayout to "+ Binder.getCallingPid());return res;
}
Session 将 relayoutWindow 转发给 WMS
com.android.server.wm.WindowManagerService#relayoutWindow
public int relayoutWindow(Session session, IWindow client, LayoutParams attrs,int requestedWidth, int requestedHeight, int viewVisibility, int flags,long frameNumber, ClientWindowFrames outFrames, MergedConfiguration mergedConfiguration,SurfaceControl outSurfaceControl, InsetsState outInsetsState,InsetsSourceControl[] outActiveControls, Point outSurfaceSize) {Arrays.fill(outActiveControls, null);int result = 0;boolean configChanged;final int pid = Binder.getCallingPid();final int uid = Binder.getCallingUid();final long origId = Binder.clearCallingIdentity();synchronized (mGlobalLock) {...// We may be deferring layout passes at the moment, but since the client is interested// in the new out values right now we need to force a layout.mWindowPlacerLocked.performSurfacePlacement(true /* force */);//1...}Binder.restoreCallingIdentity(origId);return result;
}
在注释 1 处,执行 WindowSurfacePlacer 的 performSurfacePlacement 方法,WindowSurfacePlacer 用于定位窗口以及他们的 Surface 的位置
com.android.server.wm.WindowSurfacePlacer#performSurfacePlacement(boolean)
final void performSurfacePlacement(boolean force) {if (mDeferDepth > 0 && !force) {mDeferredRequests++;return;}int loopCount = 6;do {mTraversalScheduled = false;performSurfacePlacementLoop();//1mService.mAnimationHandler.removeCallbacks(mPerformSurfacePlacement);loopCount--;} while (mTraversalScheduled && loopCount > 0);mService.mRoot.mWallpaperActionPending = false;
}
com.android.server.wm.WindowSurfacePlacer#performSurfacePlacementLoop
private void performSurfacePlacementLoop() {...try {mService.mRoot.performSurfacePlacement();//1mInLayout = false;if (mService.mRoot.isLayoutNeeded()) {if (++mLayoutRepeatCount < 6) {requestTraversal();} else {Slog.e(TAG, "Performed 6 layouts in a row. Skipping");mLayoutRepeatCount = 0;}} else {mLayoutRepeatCount = 0;}if (mService.mWindowsChanged && !mService.mWindowChangeListeners.isEmpty()) {mService.mH.removeMessages(REPORT_WINDOWS_CHANGE);mService.mH.sendEmptyMessage(REPORT_WINDOWS_CHANGE);}} catch (RuntimeException e) {mInLayout = false;Slog.wtf(TAG, "Unhandled exception while laying out windows", e);}
}
在注释 1 处,mService.mRoot 是 RootWindowContainer 类型
com.android.server.wm.RootWindowContainer#performSurfacePlacement
void performSurfacePlacement() {Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "performSurfacePlacement");try {performSurfacePlacementNoTrace();} finally {Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);}
}
com.android.server.wm.RootWindowContainer#performSurfacePlacementNoTrace
void performSurfacePlacementNoTrace() {...if (SHOW_LIGHT_TRANSACTIONS) {Slog.i(TAG,">>> OPEN TRANSACTION performLayoutAndPlaceSurfaces");}Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "applySurfaceChanges");mWmService.openSurfaceTransaction();try {applySurfaceChangesTransaction();} catch (RuntimeException e) {Slog.wtf(TAG, "Unhandled exception in Window Manager", e);} finally {mWmService.closeSurfaceTransaction("performLayoutAndPlaceSurfaces");Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);if (SHOW_LIGHT_TRANSACTIONS) {Slog.i(TAG,"<<< CLOSE TRANSACTION performLayoutAndPlaceSurfaces");}}...
}
com.android.server.wm.RootWindowContainer#applySurfaceChangesTransaction
private void applySurfaceChangesTransaction() {mHoldScreenWindow = null;mObscuringWindow = null;// TODO(multi-display): Support these features on secondary screens.final DisplayContent defaultDc = mWmService.getDefaultDisplayContentLocked();final DisplayInfo defaultInfo = defaultDc.getDisplayInfo();final int defaultDw = defaultInfo.logicalWidth;final int defaultDh = defaultInfo.logicalHeight;if (mWmService.mWatermark != null) {mWmService.mWatermark.positionSurface(defaultDw, defaultDh, mDisplayTransaction);}if (mWmService.mStrictModeFlash != null) {mWmService.mStrictModeFlash.positionSurface(defaultDw, defaultDh, mDisplayTransaction);}if (mWmService.mEmulatorDisplayOverlay != null) {mWmService.mEmulatorDisplayOverlay.positionSurface(defaultDw, defaultDh,mWmService.getDefaultDisplayRotation(), mDisplayTransaction);}final int count = mChildren.size();for (int j = 0; j < count; ++j) {final DisplayContent dc = mChildren.get(j);//1dc.applySurfaceChangesTransaction();//2}// Give the display manager a chance to adjust properties like display rotation if it needs// to.mWmService.mDisplayManagerInternal.performTraversal(mDisplayTransaction);SurfaceControl.mergeToGlobalTransaction(mDisplayTransaction);
}
注释 1 处的 mChildren 在 WindowContainer 定义如下
// List of children for this window container. List is in z-order as the children appear on
// screen with the top-most window container at the tail of the list.
protected final WindowList mChildren = new WindowList();
WindowContainer 是 AppWindowToken、Task、TaskStack、DisplayContent 的基类,用于管理窗口配置。
显然 mChildren 在这里是 DisplayContent 类型的数组,即注释 2 处调用了
void applySurfaceChangesTransaction() {...Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "applyPostLayoutPolicy");try {mDisplayPolicy.beginPostLayoutPolicyLw();forAllWindows(mApplyPostLayoutPolicy, true /* traverseTopToBottom */);pendingLayoutChanges |= mDisplayPolicy.finishPostLayoutPolicyLw();} finally {Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);}if (DEBUG_LAYOUT_REPEATS) surfacePlacer.debugLayoutRepeats("after finishPostLayoutPolicyLw", pendingLayoutChanges);mInsetsStateController.onPostLayout();...}
com.android.server.wm.DisplayPolicy#finishPostLayoutPolicyLw
/*** Called following layout of all windows and after policy has been applied* to each window. If in this function you do* something that may have modified the animation state of another window,* be sure to return non-zero in order to perform another pass through layout.** @return Return any bit set of* {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_LAYOUT},* {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_CONFIG},* {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_WALLPAPER}, or* {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_ANIM}.*/
public int finishPostLayoutPolicyLw() {int changes = 0;boolean topIsFullscreen = false;// If we are not currently showing a dream then remember the current// lockscreen state. We will use this to determine whether the dream// started while the lockscreen was showing and remember this state// while the dream is showing.if (!mShowingDream) {mDreamingLockscreen = mService.mPolicy.isKeyguardShowingAndNotOccluded();}if (getStatusBar() != null) {if (DEBUG_LAYOUT) Slog.i(TAG, "force=" + mForceStatusBar+ " top=" + mTopFullscreenOpaqueWindowState);final boolean forceShowStatusBar = (getStatusBar().getAttrs().privateFlags& PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR) != 0;boolean topAppHidesStatusBar = topAppHidesStatusBar();if (mForceStatusBar || forceShowStatusBar) {if (DEBUG_LAYOUT) Slog.v(TAG, "Showing status bar: forced");// Maintain fullscreen layout until incoming animation is complete.topIsFullscreen = mTopIsFullscreen && mStatusBar.isAnimatingLw();} else if (mTopFullscreenOpaqueWindowState != null) {topIsFullscreen = topAppHidesStatusBar;// The subtle difference between the window for mTopFullscreenOpaqueWindowState// and mTopIsFullscreen is that mTopIsFullscreen is set only if the window// requests to hide the status bar. Not sure if there is another way that to be the// case though.if (!topIsFullscreen || mDisplayContent.getDefaultTaskDisplayArea().isRootTaskVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY)) {topAppHidesStatusBar = false;}}StatusBarManagerInternal statusBar = getStatusBarManagerInternal();if (statusBar != null) {statusBar.setTopAppHidesStatusBar(topAppHidesStatusBar);}}if (mTopIsFullscreen != topIsFullscreen) {if (!topIsFullscreen) {// Force another layout when status bar becomes fully shown.changes |= FINISH_LAYOUT_REDO_LAYOUT;}mTopIsFullscreen = topIsFullscreen;}if (updateSystemUiVisibilityLw()) {// If the navigation bar has been hidden or shown, we need to do another// layout pass to update that window.changes |= FINISH_LAYOUT_REDO_LAYOUT;}if (mShowingDream != mLastShowingDream) {mLastShowingDream = mShowingDream;mService.notifyShowingDreamChanged();}mService.mPolicy.setAllowLockscreenWhenOn(getDisplayId(), mAllowLockscreenWhenOn);return changes;
}
com.android.server.wm.DisplayPolicy#updateSystemUiVisibilityLw
/*** @return {@code true} if the update may affect the layout.*/
boolean updateSystemUiVisibilityLw() {...mDisplayContent.getInsetsPolicy().updateBarControlTarget(win);...mHandler.post(() -> {StatusBarManagerInternal statusBar = getStatusBarManagerInternal();if (statusBar != null) {final int displayId = getDisplayId();statusBar.setDisableFlags(displayId, disableFlags, cause);statusBar.onSystemBarAttributesChanged(displayId, appearance, appearanceRegions,isNavbarColorManagedByIme, behavior, isFullscreen);}});..return true;
}
com.android.server.wm.InsetsPolicy#updateBarControlTarget
void updateBarControlTarget(@Nullable WindowState focusedWin) {if (mFocusedWin != focusedWin){abortTransient();}mFocusedWin = focusedWin;boolean forceShowsSystemBarsForWindowingMode = forceShowsSystemBarsForWindowingMode();InsetsControlTarget statusControlTarget = getStatusControlTarget(focusedWin,forceShowsSystemBarsForWindowingMode);InsetsControlTarget navControlTarget = getNavControlTarget(focusedWin,forceShowsSystemBarsForWindowingMode || forceShowsNaviBar());mStateController.onBarControlTargetChanged(statusControlTarget,getFakeControlTarget(focusedWin, statusControlTarget),navControlTarget,getFakeControlTarget(focusedWin, navControlTarget));mStatusBar.updateVisibility(statusControlTarget, ITYPE_STATUS_BAR);mNavBar.updateVisibility(navControlTarget, ITYPE_NAVIGATION_BAR);
}