SurfaceFlinger 为什么不画 View,却决定屏幕最终显示什么
SurfaceFlinger 为什么不画 View,却决定屏幕最终显示什么
应用画完 View 只得到一个可供合成的 Buffer。状态栏、壁纸、应用窗口和动画 Layer 还要在同 一个刷新周期内被组合成显示输出;SurfaceFlinger 负责接收这些 Layer 的内容与状态,决定提交 给 HWC 的合成计划,但不会进入应用进程调用 View 的 draw()。
SurfaceFlinger 的输入是 Layer,不是 View 树
| 常见误解 | 正确理解 |
|---|---|
SurfaceFlinger 负责调用 View 的 draw() | App 进程完成 View 绘制;SurfaceFlinger 接收结果并合成 Layer |
| WMS 把每个窗口画到屏幕 | WMS 管窗口状态、层级和几何;SurfaceFlinger 处理合成状态 |
| 一个应用窗口只对应一张 Bitmap | 系统处理的是持续更新的 Buffer、Layer 状态和同步信息 |
| HWC 一定比 GPU 合成快 | 合成方式由当帧内容和设备能力协商,不能脱离设备下结论 |
容易产生这些误解,是因为 App 开发者通常只看到 invalidate()、Choreographer 和 Canvas。 它们解释“应用怎样准备内容”,却没有解释多个应用、状态栏、壁纸、动画图层如何在同一刷新周期中组成最终画面。
SurfaceFlinger 合成 Layer,不绘制应用 View
SurfaceFlinger 是系统合成服务,不是 View 绘制引擎。
SurfaceFlinger 是运行在独立 native 进程中的系统服务。它接收客户端提交的 Layer 状态与 Buffer, 维护可见图层快照,组织每个显示设备的合成,再把结果交给 Hardware Composer。应用的 View 树、测量布局和 draw() 不属于它。
| 阶段 | Android 对象 | 对应职责 |
|---|---|---|
| 内容生产 | App 主线程、RenderThread、GPU | 生产一帧的像素内容 |
| 窗口管理 | WMS | 决定窗口层级、位置、可见性等逻辑状态 |
| 图层合成 | SurfaceFlinger、CompositionEngine | 收集图层状态并规划合成 |
| 显示控制器 | Hardware Composer(HWC) | 校验设备能力、提交显示并返回 fence |
比喻边界: Android 14 的真实链路包含 Binder、BLASTBufferQueue、事务、fence 和 VSync 调度;“叠胶片”只帮助理解职责,不能解释同步时序和硬件限制。
职责边界是:App 生产内容,WMS 维护窗口状态,SurfaceFlinger 组织合成,HWC 按设备能力完成 device composition 或显示提交。
一句话小结:SurfaceFlinger 决定怎样组合已有内容,但不会替 App 生成 View 内容。
Buffer 是内容,Layer 是合成状态
先记住结论:Buffer 回答“画了什么”,Layer 回答“怎样参与最终画面”。
Buffer是一帧像素内容及其描述信息。它可能由 CPU、RenderThread/GPU 或媒体组件生产。Layer是 SurfaceFlinger 服务端的合成节点,携带父子关系、位置、裁剪、透明度、层级、 变换以及当前 Buffer 等状态。Surface是生产者使用的写入入口。在普通应用窗口的 BLAST 主链中,它封装了IGraphicBufferProducer,让渲染端可以 dequeue、绘制并 queue Buffer。SurfaceControl是客户端控制 Layer 的句柄。它是SurfaceControl.Transaction的目标, 不是像素存储区。Transaction是一批 Layer 状态或 Buffer 更新。apply()表示提交这批变更, 不等于该帧已经出现在物理屏幕上。
Android 14 普通窗口通常使用 BLAST:客户端进程中的 BLASTBufferQueue 从队列取得可用 Buffer,再把 Buffer 与 Layer 状态放进事务。于是“BufferQueue 的消费者永远就是 SurfaceFlinger”这种旧式背诵并不适合直接描述这条主链。
Surface 用于提交 Buffer,SurfaceControl 用于修改 Layer 状态,Layer 是 SurfaceFlinger 合成树 中的服务端节点。
一句话小结:同一个 Layer 可以连续接收不同 Buffer,也可以在没有新 Buffer 时改变位置。
一帧怎样从应用走到显示设备
先看整条主线。图中的 Binder transaction 是合成事务,不代表 App 与 SurfaceFlinger 共享同一线程;HWC HAL 之后的具体显示驱动由设备实现。
- ① App 生产内容:主线程遍历 View 树,硬件加速路径由 RenderThread/GPU 完成相关 录制与渲染工作,最终把 Buffer queue 到客户端生产者队列。
- ② BLAST 在客户端整理事务:
onFrameAvailable()后 acquire Buffer,再用setBuffer()将它与目标 SurfaceControl 关联;这一步仍在 App 进程。 - ③ SurfaceFlinger commit:
Transaction.apply()经 Binder 提交后,SurfaceFlinger 刷新事务、Layer 快照、 Buffer 与回调状态,并判断这一周期是否必须合成。 - ④ SurfaceFlinger composite:它为物理或虚拟显示构造
CompositionRefreshArgs,收集输出与参与本帧的 Layer 前端状态。 - ⑤ CompositionEngine 执行输出流程:它更新合成状态、规划图层、准备帧, 必要时用 RenderEngine 做 client composition,再组织 present。
- ⑥ HWC 提交显示:Hardware Composer 校验设备合成能力,执行 present,返回 present/release fence。屏幕扫描输出仍发生在这个调用之后。
一句话小结:一帧不是一次函数调用,而是生产、提交、合成规划和设备呈现组成的时序链。
commit 与 composite 为什么要分开理解
先记住结论:commit() 收敛“这一帧是什么状态”,composite() 处理“怎样输出”。
SurfaceFlinger.cpp:2507 SurfaceFlinger::commit() 是 Android 14 r75 的帧提交阶段入口。 它记录 FrameTimeline 唤醒信息,刷新 Layer 快照,并根据事务和新 Buffer 判断是否需要合成。
// SurfaceFlinger.cpp:2507
bool SurfaceFlinger::commit(PhysicalDisplayId pacesetterId,
const scheduler::FrameTargets& frameTargets) {
// 省略事务刷新、Layer 快照和刷新率选择
return mustComposite && CC_LIKELY(mBootStage != BootStage::BOOTLOADER);
}SurfaceFlinger.cpp:2659 SurfaceFlinger::composite() 构造输出参数;在 SurfaceFlinger.cpp:2787,它把这些参数交给 CompositionEngine。
// SurfaceFlinger.cpp:2787
mCompositionEngine->present(refreshArgs);这两个阶段不能简单理解成“CPU 处理”和“GPU 处理”。commit() 也会执行大量状态工作; composite() 则可能根据 HWC 结果混合 device composition 与 client composition。
一句话小结:提交事务成功只说明状态进入合成侧,不证明 present fence 已经完成。
client composition 与 device composition 怎样分工
先记住结论:合成策略是 SurfaceFlinger、CompositionEngine 与 HWC 针对当帧协商的结果。
在 Output.cpp:433 Output::present() 中,CompositionEngine 依次规划、准备、完成帧并 释放 Layer。Output.cpp:1125 chooseCompositionStrategy() 会请求合成策略,随后在 Output.cpp:1131 applyCompositionStrategy() 应用 HWC 返回的变化。
// Output.cpp:459
updateColorProfile(refreshArgs);
updateCompositionState(refreshArgs);
planComposition();
writeCompositionState(refreshArgs);- client composition:SurfaceFlinger 使用 RenderEngine/GPU 把一组 Layer 合成到 client target,再交给 HWC。
- device composition:HWC/显示硬件直接处理符合设备能力的 Layer。
一帧可以同时包含两种方式。旋转、缩放、颜色空间、受保护内容、可用硬件平面和带宽都会 影响策略,因此不能把“尽量走 HWC”写成跨设备的固定优化结论。
最后,HWComposer.cpp:570 presentAndGetReleaseFences() 进入设备呈现路径, HWComposer.cpp:593 present() 提交显示,之后取得 release fence。fence 表示异步工作间的 依赖与完成边界,不是“越少越快”的开关。
验证与排障
环境:主机连接允许 adb shell dumpsys 的调试设备,并让目标应用保持前台。
adb shell dumpsys SurfaceFlinger --list
adb shell dumpsys SurfaceFlinger预期:--list 输出当前 Layer 名称快照;完整 dump 可观察显示设备、Layer、合成或调度相关 状态。具体字段会随 Android 小版本、build 类型和厂商修改而变化。
限制:Layer 名称存在不代表它已有 Buffer、处于可见区域或已按时 present;一次 dump 也不能 还原连续帧的因果链。需要分析卡顿时,应使用第三章介绍的 FrameTimeline 和 trace。
源码入口
从窗口状态判断首帧完成时,应同时参考 窗口何时真正变得可见,避免把 Layer 存在当成画面已显示。
源码基准:android-14.0.0_r75。
以下路径默认位于 frameworks/native/services/surfaceflinger/:
| 文件 | 关键位置 | 作用 |
|---|---|---|
SurfaceFlinger.cpp | 2507 行 SurfaceFlinger::commit() | 刷新帧状态并判断是否需要合成 |
SurfaceFlinger.cpp | 2659 行 SurfaceFlinger::composite() | 为各显示输出准备合成参数 |
SurfaceFlinger.cpp | 2787 行 mCompositionEngine->present() | 把输出交给 CompositionEngine |
CompositionEngine/src/Output.cpp | 433 行 Output::present() | 规划、准备、合成并呈现输出 |
CompositionEngine/src/Output.cpp | 1125 行 chooseCompositionStrategy() | 与 HWC 协商当帧合成策略 |
DisplayHardware/HWComposer.cpp | 570 行 presentAndGetReleaseFences() | 提交显示并取得同步 fence |