窗口何时真正变得可见
窗口何时真正变得可见
addWindow() 返回成功后仍可能黑屏,因为“WMS 已有窗口记录”之后还要经历 Surface 创建、 应用提交首个 Buffer、SurfaceFlinger 接纳 Layer 并完成合成。排查首帧问题必须明确当前证据 对应哪一个完成点。
可见状态不等于屏幕已有像素
| 常见误解 | 正确理解 |
|---|---|
| 窗口可见 = 屏幕上已经有画面 | 窗口可见只是 WMS 的逻辑状态,画面要等 Buffer 提交并合成 |
| 加窗成功 = Surface 已创建 | Surface 通常要等第一次 relayout 才创建 |
“窗口在系统里有记录”和“屏幕上出现了内容”之间隔着三层:Surface 存在、Buffer 有数据、Layer 参与合成。任一层缺失都可能黑屏,但原因完全不同。
四个完成点
逐步解释:
- ① 已注册:
addWindow()返回成功,WindowState 存在于mWindowMap。 - ② Surface 已创建:第一次 relayout 时 WMS 调用
createSurfaceLocked(),创建 SurfaceControl。 - ③ Buffer 已提交:应用渲染线程把帧交给 BLASTBufferQueue,缓冲区进入系统。
- ④ 已合成:SurfaceFlinger 把该 Layer 合入输出帧,屏幕显示。
每个节点都能用不同命令观察:WindowState 看 dumpsys window,Layer 看 dumpsys SurfaceFlinger --list,Buffer 看 SurfaceFlinger 状态与帧时间线。
WMS 的绘制状态机
WindowStateAnimator 用 mDrawState 记录绘制进度(WindowStateAnimator.java:122-134):
| 状态 | 含义 |
|---|---|
NO_SURFACE | 还没有 Surface |
DRAW_PENDING | 等待应用绘制 |
COMMIT_DRAW_PENDING | 绘制完成、等待提交 |
READY_TO_SHOW | 可以显示 |
HAS_DRAWN | 已经显示过一帧 |
WindowState.hasDrawn() 要求 mDrawState 至少是 READY_TO_SHOW(WindowState.java:2009-2013)。也就是说,WMS 判定“画过”必须等到提交阶段之后,而不是窗口一可见就算。
源码证据
阅读目标:确认 Surface 由 WMS 在 relayout 时创建,首帧由应用通过 Binder 上报。
正文指针:WindowManagerService.java:2413 / 2660 / 2694;ViewRootImpl.java:2517 / 4855。
// WindowManagerService.java:2413
result = createSurfaceControl(outSurfaceControl, result, win, winAnimator);// WindowStateAnimator.java:271
WindowSurfaceController createSurfaceLocked() {// ViewRootImpl.java:4855
mWindowSession.finishDrawing(mWindow, t, seqId);这段代码证明: relayout 时 WMS 创建 SurfaceControl 并返回给应用;应用画完首帧后调用 finishDrawing(),WMS 的 finishDrawingWindow()(WindowManagerService.java:2694)推进绘制状态。
BLAST 连接两侧
应用侧 ViewRootImpl 用 BLASTBufferQueue 连接 SurfaceControl 与 BufferQueue(ViewRootImpl.java:2517),mSurface.transferFrom(blastSurface) 让绘制面指向新 Surface(同文件 2529 行)。系统侧 WindowSurfaceController 用 win.makeSurface().setBLASTLayer().build() 创建 Layer(WindowSurfaceController.java:73-83)。Buffer 流向合成侧的细节见Surface 创建篇与SurfaceFlinger 概念篇。
源码入口
源码基准:android-14.0.0_r75。
以下文件默认位于 frameworks/base/,表中省略该前缀:
| 文件 | 关键位置 | 作用 |
|---|---|---|
services/core/java/com/android/server/wm/WindowStateAnimator.java | 271 行 createSurfaceLocked();122-134 行 mDrawState 常量;~306 行 w.setHasSurface(true) | Surface 创建与绘制状态 |
services/core/java/com/android/server/wm/WindowSurfaceController.java | 43 行 class WindowSurfaceController;73-83 行 .setBLASTLayer().build() | 服务端 Layer 创建 |
services/core/java/com/android/server/wm/WindowManagerService.java | 2413 行 createSurfaceControl(...);2660 行 createSurfaceLocked();2694 行 finishDrawingWindow() | relayout 创建与首帧通知 |
services/core/java/com/android/server/wm/WindowState.java | 2009-2013 行 hasDrawn() | 已绘制判定 |
core/java/android/view/ViewRootImpl.java | 2517 行 new BLASTBufferQueue(...);2529 行 mSurface.transferFrom(...);4855 行 mWindowSession.finishDrawing(...) | 应用侧 Buffer 连接与上报 |
frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp | 5903 行 createLayer();5942 行 addClientLayer(...);2659 行 composite(...) | 合成侧 Layer 与合成 |