第1章:SurfaceFlinger 合成管道全景
1.1 合成流程概览
Android 的显示系统由 SurfaceFlinger 服务统一管理。每帧画面需经过以下核心步骤才能呈现在屏幕上:
- App 提交图层 — 应用通过 OpenGL/Vulkan 绘制完成后,将缓冲区(Buffer)通过 BufferQueue 发送给 SurfaceFlinger。
- 合成决策 — SurfaceFlinger 收集所有可见图层(Layer),根据硬件能力、图层属性和显示状态决定合成方式:使用 HWC(硬件合成)或 GPU 合成。
- 合成执行 — HWC 直接将图层叠加到显示硬件;GPU 合成则通过 OpenGL ES 将多个图层渲染到目标缓冲区。
- 送显(Present) — 合成结果通过 Display 接口提交到显示控制器,等待下一个 Vsync 信号刷新。
关键指标: 每帧从 App 提交到显示输出的总延迟直接影响帧率稳定性,SurfaceFlinger 的合成策略是优化该延迟的核心。
1.2 HWC 与 GPU 合成对比
| 特性 | HWC 合成 | GPU 合成 |
|---|---|---|
| 执行单元 | 显示硬件(DisplayProcessor) | GPU(Graphics Processor) |
| 功耗 | 低(硬件叠加,无需整体渲染) | 较高(需逐帧渲染合成) |
| 性能开销 | 几乎没有 CPU/GPU 占用 | 消耗 GPU 时间片,可能拖慢渲染 |
| 适用场景 | 桌面、游戏、视频等有专用合成块 | 复杂 UI 动画、动态模糊、特效 |
| 可编程性 | 低(由硬件驱动固定处理) | 高(自定义着色器) |
调优要点: 在帧率不稳定时,优先检查 HWC 是否退化为 GPU 合成(通过
dumpsys SurfaceFlinger 查看 compositionType 字段)。强制 HWC 合成能降低 GPU 负载,改善帧率抖动。
1.3 BufferQueue 传递机制
BufferQueue 是 Layer 与 SurfaceFlinger 之间的生产者-消费者模型:
- 生产者(App 端):调用
dequeueBuffer()获取空闲缓冲区,绘制后调用queueBuffer()交给 BufferQueue。 - 消费者(SurfaceFlinger):在 Vsync 到来时调用
acquireBuffer()取出最新缓冲区,合成完成后调用releaseBuffer()归还。 - 同步机制:使用
Fence文件描述符确保 GPU 或 HWC 完成读写后才进行下一步操作,避免画撕裂。
# 查看 BufferQueue 状态(示例输出片段)
adb shell dumpsys SurfaceFlinger | grep -A 30 "BufferQueue"
[VRI[0]] layer: com.example.app#0
mQueue: BufferQueue
mSlot[0]: buffer=0x... state=FREE
mSlot[1]: buffer=0x... state=QUEUED
mSlot[2]: buffer=0x... state=ACQUIRED
1.4 FrameTimeline 帧时间线
FrameTimeline 是 Android 10+ 引入的帧时间追踪子系统,记录每一帧从 App 绘制到 SurfaceFlinger 合成再到 Display 呈现的完整时间线。关键时间戳包括:
- startTime — 应用开始渲染的时间(Choreographer 回调)
- endTime — 应用提交缓冲区的时间(queueBuffer)
- presentTime — 预期的屏幕刷新时间(HWC 返回的 Present 时间)
- actualPresentTime — 实际显示到屏幕上的时间(通过硬件 vsync 反馈)
通过分析 FrameTimeline 可以定位超时帧、丢帧以及合成延迟过大的环节。
注意: 在 Android 12 及之后,FrameTimeline 的数据通过
SurfaceFlinger 的 dump 或 FrameTimelineInspector 工具获取。若 presentTime - endTime 超过 16ms(60fps 场景),说明合成阶段存在瓶颈。