1. Relayout
前面介绍过当应用进程Resume的时候,会走到ViewRootImpl.java的setView, 在其中会调用到WMS的addWindow,其中会创建WindowState对象,将其挂载到窗口层级树上,并将WindowState对象和对应的Client(在ViewRootImpl中的W类对象,继承自binder,可跨进程传递) 存入到WMS的
HashMap<IBinder, WindowState> mWindowMap
在ViewRootImpl.java的setView中,还会调用requestLayout,其中会触发一次vsync,当vsync周期到时,会回调到ViewRootImpl.java的performTraversals函数,在其中又走到relayoutWindow,在relayoutWindow里调用mWindowSession.relayout,通过WindowSession调用到
WMS的relayoutWindow。relayoutWindow函数代码非常多,所以还是分段分析:
1.1 get WindowState
publicintrelayoutWindow(Sessionsession,IWindowclient,LayoutParamsattrs,intrequestedWidth,intrequestedHeight,intviewVisibility,intflags,longframeNumber,ClientWindowFramesoutFrames,MergedConfigurationmergedConfiguration,SurfaceControloutSurfaceControl,InsetsStateoutInsetsState,InsetsSourceControl[]outActiveControls,PointoutSurfaceSize){...// 1finalWindowStatewin=windowForClientLocked(session,client,false);...WindowStateAnimatorwinAnimator=win.mWinAnimator;if(viewVisibility!=View.GONE){// 2win.setRequestedSize(requestedWidth,requestedHeight);}...// 3win.setViewVisibility(viewVisibility);mark 1: 通过ViewRootImpl传递来的client(ViewRootImpl中的W类对象),从mWindowMap取到WindowState对象。
mark 2: 把应用端请求的大小,保存到WindowState下.
mark 3: 设置窗口可见 viewVisibility = VISIBLE
1.2 createSurfaceControl
if(shouldRelayout){try{// 1result=createSurfaceControl(outSurfaceControl,result,win,winAnimator);}catch(Exceptione){...}privateintcreateSurfaceControl(SurfaceControloutSurfaceControl,intresult,WindowStatewin,WindowStateAnimatorwinAnimator){...WindowSurfaceControllersurfaceController;try{Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER,"createSurfaceControl");// 1 创建“Buff”类型SurfacesurfaceController=winAnimator.createSurfaceLocked(win.mAttrs.type);}finally{Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);}if(surfaceController!=null){// 2 赋值给`outSurfaceControl`,`outSurfaceControl`是出参。surfaceController.getSurfaceControl(outSurfaceControl);ProtoLog.i(WM_SHOW_TRANSACTIONS,"OUT SURFACE %s: copied",outSurfaceControl);...}// WindowStateAnimator.javaWindowSurfaceControllercreateSurfaceLocked(intwindowType){...// 1resetDrawState();...// 2mSurfaceController=newWindowSurfaceController(attrs.getTitle().toString(),width,height,format,flags,this,windowType);mark 1:resetDrawState里面会设置mDrawState = DRAW_PENDING;
mark 2: 真正创建SurfaceControl的地方,创建后设置为“Buff”图层
下面介绍一下
mDrawState的取值和涵义:NO_SURFACE = 0, 窗口还未创建 Surface(绘制载体),是窗口初始化的初始状态;窗口隐藏 / 销毁后也会回到此状态。
DRAW_PENDING = 1, Surface 已创建,但窗口还未开始首次绘制;此时 Surface 处于隐藏状态,屏幕上不可见。
COMMIT_DRAW_PENDING = 2, 窗口已完成首次绘制,但绘制结果还未提交;Surface 仍隐藏,需等下一次布局执行时提交绘制结果。
READY_TO_SHOW = 3, 窗口绘制已提交,但 Surface 暂不显示;用于 “令牌级窗口同步”(比如 Activity 下所有窗口都准备好后再一起显示,避免闪屏)
HAS_DRAWN = 4, 窗口的 Surface 已真正显示在屏幕上,完成 “首次显示”;后续窗口刷新 / 重绘不会改变此状态(仅标记首次显示完成)。
1.3 performSurfacePlacement 计算窗口大小
继续分析WMS的relayoutWindow
mWindowPlacerLocked.performSurfacePlacement(true/* force */);// WindowManagerService.javaperformSurfacePlacementLoop();// WindowSurfacePlacer.javamService.mRoot.performSurfacePlacement();// WindowSurfacePlacer.javaperformSurfacePlacementNoTrace();// RootWindowContainer.javadc.applySurfaceChangesTransaction();// RootWindowContainer.java 遍历所有显示设备,让每个设备处理旗下窗口的 Surface 变更performLayout(repeats==1,false/* updateInputWindows */);// DisplayContent.javaperformLayoutNoTrace(initial,updateInputWindows);// DisplayContent.javaforAllWindows(mPerformLayout,true/* traverseTopToBottom */);// DisplayContent.javaforAllWindows(wrapper,traverseTopToBottom);// WindowContainer.java////////////////////////////// WindowContainer.javabooleanforAllWindows(ToBooleanFunction<WindowState>callback,booleantraverseTopToBottom){if(traverseTopToBottom){for(inti=mChildren.size()-1;i>=0;--i){if(mChildren.get(i).forAllWindows(callback,traverseTopToBottom)){returntrue;}}}else{finalintcount=mChildren.size();for(inti=0;i<count;i++){if(mChildren.get(i).forAllWindows(callback,traverseTopToBottom)){returntrue;}}}returnfalse;}// WindowState.java@OverridebooleanforAllWindows(ToBooleanFunction<WindowState>callback,booleantraverseTopToBottom){if(mChildren.isEmpty()){// The window has no children so we just return it.returnapplyInOrderWithImeWindows(callback,traverseTopToBottom);}if(traverseTopToBottom){returnforAllWindowTopToBottom(callback);}else{returnforAllWindowBottomToTop(callback);}}// WindowState.javaprivatebooleanapplyInOrderWithImeWindows(ToBooleanFunction<WindowState>callback,booleantraverseTopToBottom){if(traverseTopToBottom){if(applyImeWindowsIfNeeded(callback,traverseTopToBottom)||callback.apply(this)){returntrue;}}else{if(callback.apply(this)||applyImeWindowsIfNeeded(callback,traverseTopToBottom)){returntrue;}}returnfalse;}forAllWindows的实现又是一个递归,来遍历窗口层级树。我们之前分析过这样的情形。在WindowContainer的子类里面,虽然也有实现forAllWindows,但
最后还是调用父类WindowContainer的实现,从而继续递归。只有在子类WindowState中,它的实现是打破了递归的,并且这样也合理,因为其他的窗口层级节点都是window容器,WindowState是负责显示的。
WindowState的forAllWindows,会调用到applyInOrderWithImeWindows,在其中会调用参数callback的apply,
callback是上面走到DisplayContent,在调用performLayoutNoTrace时传递的mPerformLayout,
mPerformLayout是一个Consumer<WindowState>对象(理解为一个lambda表达式对象),那么上面调用它的apply,其实就是执行这个对象,
// DisplayContent.javaprivatefinalConsumer<WindowState>mPerformLayoutAttached=w->{...getDisplayPolicy().layoutWindowLw(w,w.getParentWindow(),mDisplayFrames);...};DisplayPolicy.java的layoutWindowLw是 WMS 中单个窗口 Frame(位置 / 大小)计算的最终实现,涵盖系统栏、刘海屏、输入法、厂商定制等所有场景的适配。比如你想让弹窗避开系统栏,便可以在该函数中做统一处理重新计算窗口位置以及宽高。
1.4 返回窗口大小给应用端
win.fillClientWindowFramesAndConfiguration(outFrames,mergedConfiguration,false/* useLatestConfig */,shouldRelayout);将前面1.3 中计算好的窗口大小复制给outFrames,而该参数又是从app侧传递过来的。所以最后就将计算好的窗口大小返回给了APP。
2. FinishDrawing
在上面relayout结束后,应用进程就开始draw了,draw之后会调用WMS的finishDrawingWindow
// WindowManagerService.javavoidfinishDrawingWindow(Sessionsession,IWindowclient,...WindowStatewin=windowForClientLocked(session,client,false);...if(win!=null&&win.finishDrawing(postDrawTransaction)){...mWindowPlacerLocked.requestTraversal();}...}2.1 COMMIT_DRAW_PENDING
在finishDrawingWindow中,也会通过HashMap<IBinder, WindowState> mWindowMap先找到对应的WindowState对象,然后调用WindowState的finishDrawing,其中又会调用WindowStateAnimator.java的finishDrawingLocked, 里面会设置:
mDrawState = COMMIT_DRAW_PENDING;
这里要说一下,每个WindowState对应一个WindowStateAnimator。
2.2 requestTraversal
之后调用mWindowPlacerLocked.requestTraversal();
requestTraversal()// WindowSurfacePlacer.javamService.mAnimationHandler.post(mPerformSurfacePlacement);// WindowSurfacePlacer.javaperformSurfacePlacement();// WindowSurfacePlacer.javaperformSurfacePlacement(false/* force */);// WindowSurfacePlacer.javaperformSurfacePlacementLoop()// WindowSurfacePlacer.javamService.mRoot.performSurfacePlacement();// WindowSurfacePlacer.javaperformSurfacePlacementNoTrace();// RootWindowContainer.javamWmService.openSurfaceTransaction();applySurfaceChangesTransaction()// RootWindowContainer.javadc.applySurfaceChangesTransaction();// DisplayContent.java// 1forAllWindows(mApplySurfaceChangesTransaction,true/* traverseTopToBottom */);// 2prepareSurfaces();mWmService.openSurfaceTransaction();// 提交事物上面的调用栈和relayout流程中,都到了一起,都走到了performSurfacePlacement函数,这2次的调用肯定会根据一些状态变量觉得哪次调用走,哪次不走。后续分析。
mark 1:前面我们已经分析过forAllWindows的套路,所以不再分析,直接看最后执行的Consumer对象mApplySurfaceChangesTransaction,
2.3 mApplySurfaceChangesTransaction
核心作用:单个窗口 Surface 事务的核心应用入口,完成遮挡状态、显示属性、绘制提交、壁纸适配等状态同步,是 “布局计算” 到 “Surface 渲染” 的关键桥梁;
核心逻辑:
- 遮挡优化:标记完全遮挡屏幕的窗口,减少后方窗口渲染开销;
- 状态流转:通过
commitFinishDrawingLocked推进绘制状态,为performShowLocked铺路; - 联动适配:同步壁纸可见性、Activity 绘制状态、信标窗口,保证显示一致性;
// DisplayContent.javaprivatefinalConsumer<WindowState>mApplySurfaceChangesTransaction=w->{...if(w.mHasSurface){// Take care of the window being ready to display.// 参考2.3.1finalbooleancommitted=winAnimator.commitFinishDrawingLocked();...w.mHasSurface在requestLayout阶段就创建了surface,并设置 = true 了,所以会走进winAnimator.commitFinishDrawingLocked。
2.3.1 READY_TO_SHOW
// WindowStateAnimator.javabooleancommitFinishDrawingLocked(){...// 1mDrawState=READY_TO_SHOW;booleanresult=false;finalActivityRecordactivity=mWin.mActivityRecord;if(activity==null||activity.canShowWindows()||mWin.mAttrs.type==TYPE_APPLICATION_STARTING){// 2result=mWin.performShowLocked();}returnresult;mark 1: 重要的状态设置:
mDrawState = READY_TO_SHOW;
mark 2: 如果是系统窗口或者activity.canShowWindows == true(大多数情况下为true),走进mWin.performShowLocked,
2.3.2 HAS_DRAWN
WindowState.java的performShowLocked中会设置:
mWinAnimator.mDrawState = HAS_DRAWN;
mDrawState = HAS_DRAWN:一旦设置,窗口永久标记为 “已首次显示”,后续仅刷新内容,不再走首次显示流程。
这个方法是 Android 窗口显示的 “最终开关”,所有上游的布局计算、状态流转、Surface 准备,最终都通过这一步触发窗口真正显示在屏幕上。
虽然状态设置为HAS_DRAWN,但其实并没有真正show出来,因为没有看到和surfaceflinger的交互,还要继续往下看。
2.4 prepareSurfaces
回到2.2,DisplayContent.java的applySurfaceChangesTransaction,在执行完lamda表达式mApplySurfaceChangesTransaction之后,
继续执行prepareSurfaces:
// DisplayContent@OverridevoidprepareSurfaces(){Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER,"prepareSurfaces");try{// 1. 拿到事务finalTransactiontransaction=getPendingTransaction();// 2. 调用父类方法super.prepareSurfaces();// 3. 把事务merge到全局事务,供后续统一处理SurfaceControl.mergeToGlobalTransaction(transaction);}finally{Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);}}mark 2中最后会走到WindowContainer.java的prepareSurfaces,然后再调用所有子类的prepareSurfaces,熟悉的套路。
最后走到子类WindowState.java的prepareSurfaces,在里面调用mWinAnimator.prepareSurfaceLocked(getSyncTransaction());。
最后一步步调用到WindowSurfaceController.java的showRobustly
booleanshowRobustly(SurfaceControl.Transactiont){ProtoLog.i(WM_SHOW_TRANSACTIONS,"SURFACE SHOW (performLayout): %s",title);if(DEBUG_VISIBILITY)Slog.v(TAG,"Showing "+this+" during relayout");if(mSurfaceShown){returntrue;}setShown(true);t.show(mSurfaceControl);returntrue;}1、这个日志很关键,表示 Framework 已经将 Surface 提交到 SurfaceFlinger 了。(严格来说需要等后面事务的apply)
2、将 mSurfaceShown 变量设置为true, 这个也是分析黑屏问题dump要看第一个关键变量,如果为 false 说明窗口并没有显示,可能是被遮挡了
3、这里看到 SurfaceControl.Transaction::show 的调用地方了, 这个 show 就说明需要把 Suface 显示, 也是 finishDrawingWindow 最终的结果。
2.5 提交事物
最后会到2.2的performSurfacePlacementNoTrace
在走完applySurfaceChangesTransaction后,调用mWmService.closeSurfaceTransaction("performLayoutAndPlaceSurfaces");
这里面会提交事物给sf