Android 渲染管线:Main Thread → RenderThread → SurfaceFlinger
一、整体架构概览
┌─────────────────── App 进程 ────────────────────┐ ┌──── 独立进程 ────┐
│ │ │ │
│ Main Thread RenderThread │ │ SurfaceFlinger │
│ (UI 线程) (渲染线程) │ │ (合成器进程) │
│ │ │ │
│ ┃ measure ┃ ┃ GPU 渲染 ┃ │ │ ┃ 合成所有 ┃│
│ ┃ layout ┃ sync ┃ 生成像素 ┃
BufferQueue │ ┃ Surface层 ┃│
│ ┃ draw ┃ ──────→ ┃ 填充 Buffer ┃ ────────→ │ │ ┃ 输出到屏幕 ┃│
│ ┃(记录命令)┃ ┃(执行命令) ┃ │ │ │
│ │ │ │
└───────────────────────────────────────────────────┘ └──────────────────┘
↑ ↑ ↑
CPU 操作 GPU 操作 Hardware Composer
二、三者的角色
┌─────────────────────────────────────────────────────────────────┐
│ Main Thread (UI Thread) │
│ ───────────────────── │
│ • 处理 Input 事件 │
│ • 执行动画计算 │
│ • measure / layout / draw (View树遍历) │
│ • draw 阶段:不是真正画像素,而是记录 DisplayList (RenderNode) │
│ • 产出:一棵 DisplayList 树(绘制命令记录) │
└─────────────────────────────────────────────────────────────────┘
│ sync (同步 DisplayList)
↓
┌─────────────────────────────────────────────────────────────────┐
│ RenderThread │
│ ──────────── │
│ • 接收 DisplayList │
│ • 将 DisplayList 转化为 GPU 指令 (OpenGL ES / Vulkan) │
│ • 调用 GPU 渲染像素到 GraphicBuffer │
│ • 通过 BufferQueue 将渲染好的 Buffer 提交给 SurfaceFlinger │
│ • 产出:一块填满像素的 GraphicBuffer │
└─────────────────────────────────────────────────────────────────┘
│ BufferQueue (queueBuffer)
↓
┌─────────────────────────────────────────────────────────────────┐
│ SurfaceFlinger │
│ ────────────── │
│ • 接收所有应用窗口的 GraphicBuffer │
│ • 按 Z-order 合成多个 Layer(状态栏、导航栏、App窗口...) │
│ • 通过 HWC (Hardware Composer) 或 GPU 合成 │
│ • 将最终画面提交给显示屏 │
│ • 产出:屏幕上的最终画面 │
└─────────────────────────────────────────────────────────────────┘
三、Main Thread 与 RenderThread 的交互
3.1 交互机制
Main Thread RenderThread
│ │
│ ① VSYNC-app 信号到达 │
│ Choreographer.doFrame() 被触发 │
│ │
├── input 处理 │
├── animation 计算 │
├── traversal │
│ ├── measure (计算大小) │
│ ├── layout (计算位置) │
│ └── draw (记录绘制命令) │
│ │ │
│ │ View.draw() 不直接画像素 │
│ │ 而是记录到 DisplayList 中: │
│ │ canvas.drawRect(...) │
│ │ canvas.drawText(...) │
│ │ canvas.drawBitmap(...) │
│ ↓ │
│ ② 调用 ThreadedRenderer.draw() │
│ │ │
│ │══ syncFrameState ══════════════→ │ ★ 同步点
│ │ (DisplayList 从主线程 │
│ │ 拷贝/移交到 RenderThread) │
│ │ │
│ ③ 主线程被释放 ├── 接收 DisplayList
│ 可以处理下一帧或其他事务 ├── 转化为 GPU 指令
│ ├── 调用 OpenGL/Vulkan
│ ├── GPU 渲染像素
│ ├── eglSwapBuffers
│ │ (提交 Buffer)
│ │
│ 下一个 VSYNC... │
3.2 关键同步点:syncFrameState
// ThreadedRenderer.java (简化)
void draw(View view, AttachInfo attachInfo, DrawCallbacks callbacks) {
// 1. 更新 DisplayList
updateRootDisplayList(view, callbacks);
// 2. ★ 同步到 RenderThread(这是阻塞操作)
// 主线程在这里等待 RenderThread 完成上一帧的 sync
int syncResult = nSyncAndDrawFrame(mNativeProxy, frameInfo);
// 3. sync 完成后,主线程被释放
// RenderThread 开始独立工作
}
Perfetto 中的表现:
Main Thread:
┃ doFrame ─────────────────────────────────────────────┃
┃ input ┃ anim ┃ traversal ──────────────┃ commit ─────┃
┃ ┃ ┃ measure┃layout┃ draw ──┃│ ┃
┃ ┃ ┃ ┃ ┃ record ┃│syncFrame.. ┃
│ 等待sync │
↓ │
RenderThread: │
(上一帧收尾)┃ syncFrameState ┃ issueCommands ┃ swap ┃ │
↑ │
└── 这个完成后主线程才能继续 ────────────────┘
3.3 DisplayList 的作用
Main Thread 的 draw 阶段生成 DisplayList(而非像素):
DisplayList 示例:
┌────────────────────────────────────┐
│ Save │
│ ClipRect(0, 0, 1080, 1920) │
│ DrawColor(#FFFFFF) │ ← 背景
│ Save │
│ Translate(100, 200) │
│ DrawRoundRect(0, 0, 300, 400) │ ← 卡片背景
│ DrawText("Hello", 20, 50) │ ← 文字
│ DrawBitmap(avatar, 200, 10) │ ← 图片
│ Restore │
│ DrawLine(0, 600, 1080, 600) │ ← 分割线
│ Restore │
└────────────────────────────────────┘
这些命令不会在主线程执行,
而是传递给 RenderThread,
由 RenderThread 翻译成 GPU 指令执行。
3.4 为什么要分两个线程?
Android 4.x(无 RenderThread):
Main Thread: ┃ input ┃ anim ┃ measure ┃ layout ┃ draw+GPU渲染 ────────┃
│←──────────────── 全部在主线程,容易超时 ─────────────────→│
Android 5.0+(有 RenderThread):
Main Thread: ┃ input ┃ anim ┃ measure ┃ layout ┃ draw ┃ sync ┃ ← 提前释放!
│
RenderThread: ┃ GPU渲染 ──────┃
│←── 与主线程并行 →│
好处:
- 主线程更快释放,可以处理下一帧的 input
- GPU 渲染与主线程的下一帧准备可以并行
- 流水线效率更高
四、RenderThread 与 SurfaceFlinger 的交互
4.1 BufferQueue 机制(核心桥梁)
BufferQueue(生产者-消费者模型)
RenderThread SurfaceFlinger
(Producer 生产者) (Consumer 消费者)
│ │
│ ① dequeueBuffer() │
│ ──────────────→ ┌──────────┐ │
│ 获取空闲 Buffer │ Buffer 0 │ ← FREE │
│ ←────────────── └──────────┘ │
│ ┌──────────┐ │
│ │ Buffer 1 │ ← ACQUIRED(SF在用) │
│ └──────────┘ │
│ ┌──────────┐ │
│ │ Buffer 2 │ ← QUEUED(等待消费) │
│ └──────────┘ │
│ │
│ ② GPU 渲染到 Buffer 0 │
│ (OpenGL/Vulkan 绑定此 Buffer 为 render target) │
│ │
│ ③ queueBuffer() │
│ ──────────────→ ┌──────────┐ │
│ 提交渲染完成的 │ Buffer 0 │ → QUEUED │
│ Buffer └──────────┘ │
│ │
│ ④ acquireBuffer() │
│ ┌──────────┐ ←───────────── │
│ │ Buffer 0 │ → ACQUIRED │
│ └──────────┘ SF 取走合成 │
│ │
│ ⑤ releaseBuffer() │
│ ┌──────────┐ ←───────────── │
│ │ Buffer 0 │ → FREE │
│ └──────────┘ 合成完毕,归还 │
4.2 Buffer 状态流转
dequeueBuffer() queueBuffer()
FREE ──────────────────→ DEQUEUED ──────────────→ QUEUED
↑ (App 渲染中) (等待SF消费)
│ │
│ releaseBuffer() acquireBuffer() │
└──────────────────── ACQUIRED ←───────────────────┘
(SF 合成中)
4.3 三重缓冲(Triple Buffering)
时间 →
VSYNC: ↓ ↓ ↓ ↓ ↓
Buffer A: ┃App渲染 ┃ 等待SF ┃ SF合成 ┃ FREE ┃ App渲染 ┃
Buffer B: ┃ SF合成 ┃ FREE ┃App渲染 ┃ 等待SF ┃ SF合成 ┃
Buffer C: ┃ FREE ┃App渲染 ┃ FREE ┃App渲染 ┃ FREE ┃
App: ┃渲染到A ┃渲染到C ┃渲染到A ┃渲染到C ┃渲染到A ┃
SF: ┃合成B ┃ 合成A ┃ 合成C ┃ 合成A ┃ 合成C ┃
Display: ┃显示B ┃ 显示A ┃ 显示C ┃ 显示A ┃ 显示C ┃
三个 Buffer 轮转,确保 App 和 SF 永远不需要等待
4.4 eglSwapBuffers 的本质
// RenderThread 渲染完成后调用
eglSwapBuffers(display, surface);
// 内部实际做的事:
// 1. fence sync —— 等待 GPU 真正完成渲染
// 2. queueBuffer() —— 将 Buffer 提交到 BufferQueue
// 3. dequeueBuffer() —— 获取下一个可用 Buffer(为下帧准备)
Perfetto 中的表现:
RenderThread:
┃ DrawFrame ──────────────────────────────────────────────────┃
┃ syncFrameState ┃ issueDrawCommands ────────┃ eglSwapBuffers ┃
┃ 从主线程同步 ┃ 发送 GPU 指令 ┃ 提交Buffer ┃
┃ DisplayList ┃ (可能等待 GPU fence) ┃ 到 BufferQueue┃
│
↓
BufferQueue.queueBuffer()
│
↓
SurfaceFlinger 被唤醒
五、SurfaceFlinger 的工作
5.1 合成流程
VSYNC-sf 信号到达
│
↓
┌─── SurfaceFlinger ──────────────────────────────────────┐
│ │
│ ① 收集所有 Layer 的 Buffer │
│ ├── StatusBar Surface → acquireBuffer() │
│ ├── NavigationBar Surface → acquireBuffer() │
│ ├── App Window Surface → acquireBuffer() │
│ ├── Wallpaper Surface → acquireBuffer() │
│ └── ... │
│ │
│ ② 计算可见区域、Z-order、透明度 │
│ │
│ ③ 选择合成方式 │
│ ├── HWC 合成(硬件合成器,省电高效) │
│ │ → 直接让 Display HAL 硬件叠加各 Layer │
│ │ │
│ └── GPU 合成(回退方案) │
│ → SurfaceFlinger 用 GPU 把各层画到 FrameBuffer │
│ │
│ ④ 提交到显示屏 │
│ → 调用 HWC presentDisplay() │
│ → 等待下一个 VSYNC 翻转 Buffer 显示 │
│ │
└──────────────────────────────────────────────────────────┘
5.2 多 Layer 合成示意
Z-order 从上到下
┌─────────────────────────┐
│ StatusBar Layer │ ← Surface 1
├─────────────────────────┤
│ │
│ │
│ App Window Layer │ ← Surface 2 (你的应用)
│ │
│ │
├─────────────────────────┤
│ NavigationBar Layer │ ← Surface 3
└─────────────────────────┘
↓
HWC / GPU 合成
↓
┌─────────────────────────┐
│ │
│ 最终合成画面 │ → 送往 Display
│ │
└─────────────────────────┘
六、完整的一帧渲染时序
时间 →
VSYNC-app: ↓ ↓
VSYNC-sf: ↓ ↓
Main Thread:
┃① Choreographer.doFrame() ─────────────────┃
┃ input ┃ animation ┃ traversal ───────────┃
┃ ┃ ┃ measure ┃layout┃draw ┃
┃ ┃ ┃ ┃ ┃ rec ┃
┃ ┃ ┃ ┃ ┃ ord ┃
┃ ┃ ┃ ┃ ┃ DL ┃
│
②sync │
↓
RenderThread:
┃③ DrawFrame ───────────────────┃
┃ syncState┃ draw commands ┃swap┃
┃ ┃ (GPU 工作) ┃ ┃
┃ ┃ ┃ ④ ┃
│
queueBuffer()
│
↓
BufferQueue: ┃ QUEUED ───────┃
│
acquireBuffer()
│
↓
SurfaceFlinger:
┃⑤ onVsync-sf ────────┃
┃ latchBuffer ┃
┃ calculateLayers ┃
┃ composite ──────────┃
┃ (HWC or GPU) ┃
┃ presentDisplay ─────┃
│
↓
Display: ⑥ 屏幕显示
各阶段说明
┌────┬─────────────────────┬───────────────────────────────────────┐
│阶段│ 发生位置 │ 做什么 │
├────┼─────────────────────┼───────────────────────────────────────┤
│ ① │ Main Thread │ 处理输入、动画、measure/layout/draw │
│ │ │ draw 只是记录 DisplayList 命令 │
├────┼─────────────────────┼───────────────────────────────────────┤
│ ② │ Main → Render │ syncFrameState: 同步 DisplayList │
│ │ │ 主线程阻塞等待 RenderThread 就绪 │
├────┼─────────────────────┼───────────────────────────────────────┤
│ ③ │ RenderThread │ 将 DisplayList 转为 GL/Vulkan 命令 │
│ │ │ 提交给 GPU 执行 │
├────┼─────────────────────┼───────────────────────────────────────┤
│ ④ │ Render → BufferQueue │ eglSwapBuffers → queueBuffer │
│ │ │ 将渲染好的 Buffer 放入队列 │
├────┼─────────────────────┼───────────────────────────────────────┤
│ ⑤ │ SurfaceFlinger │ VSYNC-sf 触发,取出 Buffer │
│ │ │ 合成所有 Layer,提交到 HWC │
├────┼─────────────────────┼───────────────────────────────────────┤
│ ⑥ │ Display │ HWC 在下一个 VSYNC 翻转显示新帧 │
└────┴─────────────────────┴───────────────────────────────────────┘
七、通信机制总结
Main Thread ↔ RenderThread
通信方式:进程内线程间通信
┌───────────────────────────────────────────────────────┐
│ 共享数据:DisplayList / RenderNode 树 │
│ │
│ 同步机制: │
│ • DrawFrameTask(RenderThread 的任务队列) │
│ • syncFrameState 时的互斥锁 │
│ • Fence 信号量 │
│ │
│ 交互方式: │
│ Main → Render: │
│ ThreadedRenderer.nSyncAndDrawFrame() │
│ 把 DisplayList 传递给 RenderThread │
│ │
│ Render → Main: │
│ 通过回调通知帧完成状态 │
│ FrameCompleteCallback │
└───────────────────────────────────────────────────────┘
RenderThread ↔ SurfaceFlinger
通信方式:跨进程 IPC (Binder + 共享内存)
┌───────────────────────────────────────────────────────┐
│ 共享数据:GraphicBuffer(通过共享内存/dmabuf) │
│ │
│ 控制通道: │
│ • Binder IPC │
│ - dequeueBuffer() → ISurfaceComposer │
│ - queueBuffer() → ISurfaceComposer │
│ │
│ 数据通道: │
│ • GraphicBuffer 基于共享内存 (Gralloc/ION/dmabuf) │
│ • 零拷贝!Buffer 不需要在进程间复制 │
│ • App 和 SF 通过 fd 映射同一块物理内存 │
│ │
│ 同步机制: │
│ • Fence (同步栅栏) │
│ - AcquireFence: 告诉 SF,GPU 何时渲染完成 │
│ - ReleaseFence: 告诉 App,SF 何时用完 Buffer │
└───────────────────────────────────────────────────────┘
Fence 机制详解
RenderThread BufferQueue SurfaceFlinger
│ │ │
│ queueBuffer(buffer, │ │
│ acquireFence) ──────→ │ │
│ "GPU 还没画完, │ │
│ 等这个 fence 信号再用" │ │
│ │ │
│ │ acquireBuffer() ──────→ │
│ │ + acquireFence │
│ │ │
│ │ 等待 acquireFence
│ │ 信号(GPU渲染完成)
│ │ │
│ │ fence 触发! │
│ │ 开始合成 │
│ │ │
│ │ releaseBuffer() ←────── │
│ │ + releaseFence │
│ │ "我用完了, │
│ │ 等这个 fence 再写入" │
│ │ │
│ dequeueBuffer() ──────→ │ │
│ 等待 releaseFence │ │
│ 信号后才能写入新帧 │ │
八、Perfetto 中观察三者交互
Perfetto 时间轴:
▼ com.your.app (pid: 12345)
▼ main (tid: 12345)
Choreographer#doFrame
├── input
├── animation
├── traversal
│ ├── measure
│ ├── layout
│ └── draw (record DisplayList)
└── commit ← 包含 syncFrameState
▼ RenderThread (tid: 12346)
DrawFrame
├── syncFrameState ← 从主线程接收 DisplayList
├── issueDrawCommands ← 发送 GPU 指令
├── flushDrawingCommands ← 等待 GPU 完成
└── eglSwapBuffers ← queueBuffer 提交给 SF
▼ GPU completion ← GPU fence 完成时间
┃████┃
▼ SurfaceFlinger (pid: xxx)
▼ VSYNC-app ← App 端 VSYNC
▼ VSYNC-sf ← SF 端 VSYNC
▼ Display Frames
├── Expected Timeline
└── Actual Timeline
▼ onMessageReceived ← SF 收到 Buffer 的事件
├── latchBuffer
├── calculateWorkingSet
├── composite
└── postComposition
九、一图总结
Android 渲染管线
VSYNC-app VSYNC-sf
↓ ↓
┌─────────┐ DisplayList ┌──────────┐ GraphicBuffer ┌──────────────┐
│ Main │ ──────────────→│ Render │ ───────────────→│ Surface │
│ Thread │ sync │ Thread │ BufferQueue │ Flinger │
│ │ │ │ (共享内存) │ │
│ measure │ │ GPU 渲染 │ │ 多Layer合成 │
│ layout │ │ OpenGL │ │ HWC/GPU合成 │
│ draw(DL) │ │ Vulkan │ │ │
└─────────┘ └──────────┘ └──────┬───────┘
│
进程内 进程内 跨进程 │
线程间通信 线程间通信 Binder + │
(共享内存+锁) (共享内存+锁) 共享内存 │
↓
┌──────────┐
│ Display │
│ 屏幕显示 │
└──────────┘