应用窗口的 Surface 如何创建并连接到 SurfaceFlinger
应用窗口的 Surface 如何创建并连接到 SurfaceFlinger
窗口加入 WMS 后,系统侧还需要一个可管理的 Layer,应用侧还需要一个持续生产 Buffer 的 Surface。WMS 在 relayout 路径中推动 Layer 创建并把 SurfaceControl 返回给应用,应用再用 BLASTBufferQueue 建立生产端;这两条路径会合后,窗口才具备提交画面的条件。
Surface、SurfaceControl 与 Layer 不是同一个对象
| 常见误解 | 正确理解 |
|---|---|
App 调用 setContentView() 时直接向 SurfaceFlinger 创建 Layer | WMS 在窗口 relayout 中创建窗口 Layer,App 接收控制句柄 |
Surface、SurfaceControl 和 Layer 是同一个对象的三个名字 | 三者分别是生产入口、客户端控制句柄和服务端合成节点 |
| Surface 创建完成就会立刻显示 | 还要满足有效 Buffer、可见状态、父层、裁剪、层级和 present 时序 |
| BufferQueue 必须在 SurfaceFlinger 进程里 | Android 14 普通窗口的 BLASTBufferQueue 位于客户端进程 |
SurfaceControl、Surface 与服务端 Layer 不是同一个对象
创建窗口画面需要“服务端节点”和“客户端生产端”两部分。
| 对象 | 所在位置 | 本章职责 |
|---|---|---|
| Layer | SurfaceFlinger 进程 | 保存合成树、几何、可见性和当前 Buffer 状态 |
SurfaceControl | WMS/App 的客户端句柄 | 标识并控制目标 Layer,是 transaction 的操作对象 |
| BLASTBufferQueue | App 客户端进程 | 建立 BufferQueue,协调 Buffer 与 Layer transaction |
Surface | App 渲染端 | 封装生产者接口,供渲染代码 dequeue/queue Buffer |
| Buffer | 图形内存 | 承载一帧像素及尺寸、格式、fence 等信息 |
SurfaceControl 可以存在但还没有 Buffer,Surface 也不能脱离它所连接的生产者队列解释。销毁其中一个对象,不代表其他对象在同一时刻同步消失。
四个对象按职责区分:Layer 是服务端合成节点,SurfaceControl 控制节点状态,Surface 是 Buffer 生产入口,Buffer 承载一帧内容。
一句话小结:WMS 负责先建立可管理的 Layer,App 随后建立向该 Layer 送帧的通道。
两条路径怎样在 relayout 中会合
图中 ①~⑤ 是 system_server 发起的 Layer 创建路径,⑥~⑨ 是 App 收到句柄后建立 Buffer 生产端并提交事务的路径。两条路径通过 SurfaceControl 指向同一服务端 Layer。
- ① WMS 决定创建窗口 Layer:
WindowManagerService.relayoutWindow()判断窗口需要 relayout 时,进入createSurfaceControl()。 - ② Java 跨入 JNI:
WindowSurfaceController配置 BLAST Layer 的父层、名称、格式、flags 和窗口元数据;SurfaceControl.Builder.build()最终调用nativeCreate()。 - ③ native 客户端跨 Binder:JNI 进入
SurfaceComposerClient::createSurfaceChecked(),再调用 SurfaceFlinger 返回的ISurfaceComposerClient。 - ④ SurfaceFlinger 创建服务端 Layer:
Client::createSurface()组装LayerCreationArgs,交给SurfaceFlinger::createLayer()建立 BufferStateLayer。 - ⑤~⑥ 句柄返回 App:WMS 把创建结果复制到 relayout 的 out
SurfaceControl,Binder 返回后填入ViewRootImpl.mSurfaceControl。 - ⑦ App 建立生产端:
ViewRootImpl用有效SurfaceControl创建或更新 BLASTBufferQueue,并取得供渲染器使用的Surface。 - ⑧ BLAST 在 App 内整理事务:收到 frame available 后 acquire Buffer,再对目标
SurfaceControl调用 transactionsetBuffer()。 - ⑨ 事务跨 Binder:由
SurfaceComposerClient::Transaction::apply()把整理后的状态提交给 SurfaceFlinger。
一句话小结:WMS 创建 Layer,App 建队列送 Buffer;两者不是同一个创建动作。
WMS 先创建窗口 Layer
WindowManagerService.java:2411 relayoutWindow() 在需要重新布局且调用方提供 out SurfaceControl 时调用 createSurfaceControl()。这说明创建时机属于窗口管理决策。
// WindowManagerService.java:2411
if (shouldRelayout && outSurfaceControl != null) {
result = createSurfaceControl(outSurfaceControl, result, win, winAnimator);
}WindowManagerService.java:2660 createSurfaceControl() 继续调用 WindowStateAnimator.createSurfaceLocked(),并在 2665 把结果复制到 out 对象。
WindowStateAnimator.java:271 createSurfaceLocked() 负责窗口侧创建条件、flags 与错误恢复,在 312 构造 WindowSurfaceController。后者才真正搭建 Builder:
// WindowSurfaceController.java:73
mSurfaceControl = win.makeSurface()
.setParent(win.getSurfaceControl())
.setName(name)
// 省略格式、flags 与 metadata
.setBLASTLayer().build();初始 flags 包含 SurfaceControl.HIDDEN。因此创建 Layer 与“让窗口可见”天然是两步, 不能把 build() 返回当成首帧已经上屏。
Java 请求如何跨 JNI 与 Binder 到达 SurfaceFlinger
SurfaceControl.java:965 Builder.build() 构造 Java SurfaceControl;其私有构造方法在 SurfaceControl.java:1310 调用 nativeCreate()。
// SurfaceControl.java:983
return new SurfaceControl(
mSession, mName, mWidth, mHeight, mFormat, mFlags, mParent, mMetadata,
mLocalOwnerView, mCallsite);JNI 的 android_view_SurfaceControl.cpp:467 nativeCreate() 取得 SurfaceComposerClient,在 494 调用 createSurfaceChecked()。随后链路进入:
SurfaceComposerClient.cpp:2457 createSurfaceChecked()
→ 2468 mClient->createSurface() // Binder 请求
Client.cpp:52 Client::createSurface() // SurfaceFlinger Binder 线程
→ 60 mFlinger->createLayer()
SurfaceFlinger.cpp:5903 createLayer()
→ 5915 createBufferStateLayer()
→ 5942 addClientLayer()SurfaceFlinger::createLayer() 还会返回 Layer handle、id、name 和 transform hint。客户端持有的是指向服务端对象的控制信息,不是把整个 Layer C++ 对象搬进 system_server。
App 如何基于返回的 SurfaceControl 建立 BLASTBufferQueue
ViewRootImpl.java:8897 relayoutWindow() 通过 IWindowSession.relayout() 把 mSurfaceControl 作为 out 参数。返回后,ViewRootImpl.java:8969 检查句柄有效,再调用 updateBlastSurfaceIfNeeded()。
// ViewRootImpl.java:2517
mBlastBufferQueue = new BLASTBufferQueue(mTag, mSurfaceControl,
mSurfaceSize.x, mSurfaceSize.y, mWindowAttributes.format);
Surface blastSurface = mBlastBufferQueue.createSurface();
mSurface.transferFrom(blastSurface);Java BLASTBufferQueue.createSurface() 从 adapter 的 IGraphicBufferProducer 创建 Surface。 native 构造方法在 BLASTBufferQueue.cpp:177 调用 createBufferQueue(),说明队列建立在 调用它的 App 客户端进程,而不是 SurfaceFlinger 服务进程。
当生产者 queue 新 Buffer,BLASTBufferQueue.cpp:714 onFrameAvailable() 被调用。 内部 acquire 后,BLASTBufferQueue.cpp:616 执行:
// BLASTBufferQueue.cpp:616
t->setBuffer(mSurfaceControl, buffer, fence, bufferItem.mFrameNumber, mProducerId,
releaseBufferCallback);这一行仍发生在 App 客户端进程:它把 Buffer、acquire fence 和 frame number 写进目标 Layer 的 transaction, 是“Surface 生产内容”与“SurfaceControl 控制 Layer”会合的位置。当该笔事务由 BLAST 直接提交时, BLASTBufferQueue.cpp:673-675 调用 Transaction::apply(),这才通过 Binder 进入 SurfaceFlinger。
创建完成为什么不等于首帧可见
先记住结论:至少要分别证明 Layer、Buffer 和可见合成状态。
| 状态 | 可能现象 | 第一检查点 |
|---|---|---|
| Layer 未创建或句柄无效 | App 无法建立正常绘制目标 | WMS relayout 结果、创建异常日志 |
| Layer 已创建但没有有效 Buffer | Layer 名称存在,内容仍为空 | BLAST 生产、queue/acquire 与首帧回调 |
| Layer 与 Buffer 存在但不可见 | 黑屏、被裁掉或被其他层覆盖 | hidden、父层、alpha、crop、z-order |
| 已提交但未按时 present | 卡顿或旧帧停留 | FrameTimeline、fence、合成与 HWC 时序 |
SurfaceControl 初始 hidden、App 首帧生产、WMS show transaction 和 SurfaceFlinger present 属于不同条件。排查黑屏时只看到 Layer 名称,证据仍不完整。
验证与排障
环境:主机连接调试设备,让目标 Activity 保持前台。
adb shell dumpsys window windows
adb shell dumpsys SurfaceFlinger --list预期:window dump 可定位目标 WindowState 及其可见/绘制状态;SurfaceFlinger 列表可能找到 相应 Layer 名称。厂商可调整字段和命名,二者也不是同一时刻采样。
限制:名称相似不能单独证明 WindowState、SurfaceControl、BLAST 队列和当前 Buffer 一一 对应。需要连续时序时使用 trace;需要判断哪段超时时进入下一章。
源码入口
对象创建完成后还要等待首个 Buffer 与合成结果,完成点见 窗口何时真正变得可见。
源码基准:android-14.0.0_r75。
| 文件 | 关键位置 | 作用 |
|---|---|---|
frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java | 2651 行 createSurfaceControl() | 在 relayout 中创建并返回窗口 SurfaceControl |
frameworks/base/services/core/java/com/android/server/wm/WindowStateAnimator.java | 271 行 createSurfaceLocked() | 判断并发起窗口 Layer 创建 |
frameworks/base/services/core/java/com/android/server/wm/WindowSurfaceController.java | 61 行构造方法 | 配置父层、metadata 与 BLAST Layer |
frameworks/base/core/java/android/view/SurfaceControl.java | 965 行 Builder.build() | 从 Java Builder 进入 native 创建 |
frameworks/base/core/jni/android_view_SurfaceControl.cpp | 467 行 nativeCreate() | 进入 SurfaceComposerClient |
frameworks/native/libs/gui/SurfaceComposerClient.cpp | 2457 行 createSurfaceChecked() | 通过 Binder 请求创建 Layer |
frameworks/native/services/surfaceflinger/Client.cpp | 52 行 Client::createSurface() | SurfaceFlinger 客户端 Binder 入口 |
frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp | 5903 行 createLayer() | 建立 BufferStateLayer 并加入层级 |
frameworks/base/core/java/android/view/ViewRootImpl.java | 2500 行 updateBlastSurfaceIfNeeded() | 建立或更新 App 的 BLAST 生产端 |
frameworks/native/libs/gui/BLASTBufferQueue.cpp | 714 行 onFrameAvailable()、673 行 Transaction::apply() | 在客户端整理 Buffer,并通过 Binder 提交事务 |