SurfaceFlinger 是 Android 图形系统的核心合成引擎,运行在 Native 层的独立进程(surfaceflinger)中,负责将来自不同应用和系统组件的图形缓冲区(Buffer)合成一帧,最终输出到屏幕显示。
一、SurfaceFlinger 的定位
如果把 Android 显示系统比作一个电影后期制作团队:
| 角色 | 对应组件 | 职责 |
|---|---|---|
| 导演/编剧 | App(Framework 层) | 决定画面内容,生成画面素材 |
| 素材库 | BufferQueue | 存放待合成的帧缓冲区 |
| 后期合成师 | SurfaceFlinger | 把多个素材合成为最终画面 |
| 放映机 | Display / HWC | 把最终画面送到屏幕 |
SurfaceFlinger 本身不生产内容,它只负责收集、合成、输出。
二、在 Android 图形架构中的位置
┌─────────────────────────────────────────────────────┐
│ App 层 (Java/Kotlin) │
│ View.draw() → Canvas → Surface │
├─────────────────────────────────────────────────────┤
│ Framework 层 (Java) │
│ Surface / SurfaceControl / SurfaceSession │
├─────────────────────────────────────────────────────┤
│ Native 层 (C++) │
│ ┌──────────────┐ ┌─────────────────────┐ │
│ │ BufferQueue │ ←→ │ SurfaceFlinger │ │
│ │ (缓冲队列) │ │ (合成引擎) │ │
│ └──────────────┘ └─────────────────────┘ │
│ ↑ ↓ │
│ ┌──────────────┐ ┌─────────────────────┐ │
│ │ Gralloc │ │ HWComposer (HWC) │ │
│ │ (内存分配) │ │ (硬件合成器) │ │
│ └──────────────┘ └─────────────────────┘ │
│ ↑ ↓ │
│ ┌──────────────┐ ┌─────────────────────┐ │
│ │ 内核/驱动 │ │ Display 屏幕 │ │
│ │ (DRM/ION) │ │ │ │
│ └──────────────┘ └─────────────────────┘ │
└─────────────────────────────────────────────────────┘
三、核心概念:Surface、Layer、BufferQueue
1. Surface(表面)
- 一个 Surface 对应一块可绘制的内存区域
- App 的每个 Window(包括 Activity、Dialog、SurfaceView)都对应一个 Surface
- App 通过 Canvas 或 OpenGL ES 在 Surface 上绘制内容
2. BufferQueue(缓冲队列)
- 由 BufferQueueProducer(生产者,App 端)和 BufferQueueConsumer(消费者,SurfaceFlinger 端)组成
- 采用生产者-消费者模型,解耦了"绘制"和"合成"两个环节
- 默认使用 Triple Buffer(三重缓冲):减少 GPU 绘制与 SurfaceFlinger 合成之间的等待,提升流畅度
3. Layer(图层)
- SurfaceFlinger 内部用 Layer 对象封装一个 Surface
- 每个 Layer 包含:
- 一个 BufferQueue(获取最新一帧内容)
- 位置、大小、透明度、变换矩阵等元数据
- Z-order(层级,决定谁在上谁在下)
四、SurfaceFlinger 的工作流程
步骤 1:接收 VSync 信号
- 屏幕以固定频率刷新(60Hz/90Hz/120Hz)
- SurfaceFlinger 通过 HWComposer 接收硬件 VSync 信号
- 收到信号后,触发一帧的合成工作
步骤 2:收集所有 Layer
- SurfaceFlinger 遍历当前所有可见的 Layer
- 从每个 Layer 的 BufferQueue 中获取最新的一帧(dequeueBuffer)
- 如果某个 Layer 没有新内容,则复用上一帧
步骤 3:合成(Composition)
合成有两种方式,SurfaceFlinger 会智能选择:
| 合成方式 | 执行者 | 原理 | 性能 |
|---|---|---|---|
| GPU 合成 | GPU | 将多个 Layer 作为纹理,通过 OpenGL ES / Vulkan 渲染到 FrameBuffer | 耗电高,通用性强 |
| HWC 合成 | 显示芯片(DPU) | 硬件直接将多个 Layer 叠加输出,绕过 GPU | 省电高效,但受硬件能力限制 |
HWComposer(HWC) 是 HAL 层模块,由芯片厂商(高通、联发科等)实现。它会告诉 SurfaceFlinger:"这 3 个 Layer 我能硬件合成,剩下 2 个你交给 GPU"。
步骤 4:输出到屏幕
- 合成后的最终帧通过 DRM/KMS(Linux 显示驱动)或厂商私有驱动送到屏幕
- 屏幕在下一个 VSync 周期显示这帧画面
五、关键机制详解
1. Triple Buffer(三重缓冲)
┌─────────┐ ┌─────────┐ ┌─────────┐
│ Buffer 0│ │ Buffer 1│ │ Buffer 2│
│ 显示中 │ │ GPU绘制 │ │ 空闲 │
└─────────┘ └─────────┘ └─────────┘
- Buffer 0:正在被屏幕显示
- Buffer 1:GPU 正在绘制下一帧
- Buffer 2:空闲缓冲,App 可以立即开始画下下帧
- 作用:消除 GPU 绘制与屏幕刷新之间的等待,避免卡顿(Jank)
2. VSync 与 Choreographer
- VSync(垂直同步):屏幕硬件发出的刷新信号
- Choreographer :Framework 层的"编舞师",接收 VSync 后统一调度:
- 输入事件处理
- 动画更新
- View 测量/布局/绘制
- 提交 Buffer 到 SurfaceFlinger
- 如果 App 绘制超时(超过一个 VSync 周期),就会掉帧
3. SurfaceControl 与 Transaction
- Android 10+ 引入 SurfaceControl 和 Transaction 机制
- 允许批量修改 Layer 属性(位置、大小、透明度),原子性提交
- 是实现流畅窗口动画(如分屏、PIP 画中画)的基础
六、SurfaceFlinger 与 Framework 的关系
| Framework 调用 | 对应 SurfaceFlinger 操作 |
|---|---|
WindowManager.addView() |
创建新的 Surface/Layer |
View.invalidate() → draw() |
将内容绘制到 Surface 的 Buffer |
Surface.unlockCanvasAndPost() |
将 Buffer 提交到 BufferQueue,通知 SurfaceFlinger |
Choreographer.doFrame() |
触发整帧绘制,最终通过 Binder 调用 SurfaceFlinger |
Activity.onResume() 窗口切换 |
SurfaceFlinger 调整 Layer Z-order |
七、常见问题
| 问题 | 答案要点 |
|---|---|
| 为什么 SurfaceView 比 TextureView 更流畅? | SurfaceView 有独立 Surface,直接通过 SurfaceFlinger 合成,不经过 View 系统的重绘;TextureView 作为普通 View 的一部分,需参与 View 树的绘制和合成 |
| 掉帧(Jank)是怎么产生的? | App 绘制耗时超过 VSync 周期,或 SurfaceFlinger 合成耗时过长,导致错过屏幕刷新时机 |
| HWC 和 GPU 合成的区别? | HWC 由显示芯片硬件完成,省电且性能高,但受硬件 Layer 数量限制;GPU 合成灵活但耗电 |
| 为什么 Android 用 Triple Buffer 而不是 Double Buffer? | Triple Buffer 在 GPU 绘制和屏幕显示之间增加了一个缓冲,允许 App 提前开始下一帧绘制,减少等待 |
八、总结
SurfaceFlinger 是 Android 显示系统的"中央厨房":各 App 把做好的"菜"(Buffer)放到窗口(Layer)里,SurfaceFlinger 按顺序(Z-order)把这些菜摆盘合成,通过"传菜员"(HWC/GPU)送到"餐桌"(屏幕)。