第三板块:Android 图形渲染与窗口体系 | 第十三篇:SurfaceFlinger 与 VSYNC 信号机制
所属板块:第三板块 --- Android 图形渲染与窗口体系
前置知识:第十二篇中的 System Server 架构、Binder IPC、Surface 概念、屏幕刷新原理
本篇定位 :这是 Android 图形系统的心脏 。如果说 View 的绘制是"画家在画板上作画",那么 SurfaceFlinger 就是**"美术馆的策展人将画作挂上墙"**。本篇将彻底拆解 SurfaceFlinger 的合成算法 、VSYNC 信号的产生与分发 、Triple Buffering(三重缓冲)机制 、HWC (Hardware Composer) 的硬件叠加原理 。我们将深入 HAL 层 、Kernel 驱动 、SurfaceFlinger 进程 的源码级逻辑,揭示 Android 如何实现 60/90/120 FPS 的流畅体验。全程无 UI 优化技巧、无卡顿排查指南,仅保留 Android 图形系统的底层定义与渲染规范。
1. 核心结论先行(Thesis Statement)
Android 的图形渲染是一个生产者-消费者模型。
- SurfaceFlinger 的本质 :一个系统服务 ,也是一个合成引擎 。它运行在 System Server 之外的独立进程(有时是 Root 进程),负责接收所有应用提交的 Buffer ,并根据 Z-order(深度顺序) 、透明度(Alpha) 、裁剪区域(Crop) 将它们合成为一幅最终的 Frame ,发送给 Display(显示屏)。
- VSYNC 的本质 :垂直同步信号。由硬件(Display Panel)或软件模拟产生,频率为屏幕的刷新率(60Hz/90Hz/120Hz)。它告诉系统:"屏幕准备好了,可以换下一帧了"。
- BufferQueue 的本质 :连接生产者(App)和消费者(SurfaceFlinger)的管道 。它是一个 FIFO(先进先出) 的环形缓冲区,通常包含 3 个 Buffer(Triple Buffering)。
2. 图形架构全景图
2.1 从 View 到屏幕的数据流
#mermaid-svg-ls31Cb8XScUtOWgV{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-ls31Cb8XScUtOWgV .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-ls31Cb8XScUtOWgV .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-ls31Cb8XScUtOWgV .error-icon{fill:#552222;}#mermaid-svg-ls31Cb8XScUtOWgV .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ls31Cb8XScUtOWgV .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-ls31Cb8XScUtOWgV .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ls31Cb8XScUtOWgV .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ls31Cb8XScUtOWgV .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-ls31Cb8XScUtOWgV .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ls31Cb8XScUtOWgV .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ls31Cb8XScUtOWgV .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ls31Cb8XScUtOWgV .marker.cross{stroke:#333333;}#mermaid-svg-ls31Cb8XScUtOWgV svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ls31Cb8XScUtOWgV p{margin:0;}#mermaid-svg-ls31Cb8XScUtOWgV .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-ls31Cb8XScUtOWgV .cluster-label text{fill:#333;}#mermaid-svg-ls31Cb8XScUtOWgV .cluster-label span{color:#333;}#mermaid-svg-ls31Cb8XScUtOWgV .cluster-label span p{background-color:transparent;}#mermaid-svg-ls31Cb8XScUtOWgV .label text,#mermaid-svg-ls31Cb8XScUtOWgV span{fill:#333;color:#333;}#mermaid-svg-ls31Cb8XScUtOWgV .node rect,#mermaid-svg-ls31Cb8XScUtOWgV .node circle,#mermaid-svg-ls31Cb8XScUtOWgV .node ellipse,#mermaid-svg-ls31Cb8XScUtOWgV .node polygon,#mermaid-svg-ls31Cb8XScUtOWgV .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-ls31Cb8XScUtOWgV .rough-node .label text,#mermaid-svg-ls31Cb8XScUtOWgV .node .label text,#mermaid-svg-ls31Cb8XScUtOWgV .image-shape .label,#mermaid-svg-ls31Cb8XScUtOWgV .icon-shape .label{text-anchor:middle;}#mermaid-svg-ls31Cb8XScUtOWgV .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-ls31Cb8XScUtOWgV .rough-node .label,#mermaid-svg-ls31Cb8XScUtOWgV .node .label,#mermaid-svg-ls31Cb8XScUtOWgV .image-shape .label,#mermaid-svg-ls31Cb8XScUtOWgV .icon-shape .label{text-align:center;}#mermaid-svg-ls31Cb8XScUtOWgV .node.clickable{cursor:pointer;}#mermaid-svg-ls31Cb8XScUtOWgV .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-ls31Cb8XScUtOWgV .arrowheadPath{fill:#333333;}#mermaid-svg-ls31Cb8XScUtOWgV .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-ls31Cb8XScUtOWgV .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-ls31Cb8XScUtOWgV .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ls31Cb8XScUtOWgV .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-ls31Cb8XScUtOWgV .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ls31Cb8XScUtOWgV .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-ls31Cb8XScUtOWgV .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-ls31Cb8XScUtOWgV .cluster text{fill:#333;}#mermaid-svg-ls31Cb8XScUtOWgV .cluster span{color:#333;}#mermaid-svg-ls31Cb8XScUtOWgV div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-ls31Cb8XScUtOWgV .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-ls31Cb8XScUtOWgV rect.text{fill:none;stroke-width:0;}#mermaid-svg-ls31Cb8XScUtOWgV .icon-shape,#mermaid-svg-ls31Cb8XScUtOWgV .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ls31Cb8XScUtOWgV .icon-shape p,#mermaid-svg-ls31Cb8XScUtOWgV .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-ls31Cb8XScUtOWgV .icon-shape .label rect,#mermaid-svg-ls31Cb8XScUtOWgV .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ls31Cb8XScUtOWgV .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-ls31Cb8XScUtOWgV .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-ls31Cb8XScUtOWgV :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 显示硬件
SurfaceFlinger 进程
应用进程
绘制指令
光栅化
GPU 上传
渲染到
dequeueBuffer
queueBuffer
合成
Present
View.draw()
Canvas
SkBitmap (CPU 内存)
OpenGL ES / Vulkan
Surface
BufferQueue
SurfaceFlinger
HWC (Hardware Composer)
LCD / OLED Panel
2.2 核心角色定义
| 角色 | 职责 | 学术定义 |
|---|---|---|
| Producer (生产者) | 应用进程 | 通过 Surface 接口向 BufferQueue 填充图像数据。 |
| BufferQueue | 缓冲区队列 | 管理 GraphicBuffer 的申请、归还和流转。 |
| Consumer (消费者) | SurfaceFlinger | 从 BufferQueue 中取出 GraphicBuffer,进行合成。 |
| HWC | 硬件合成器 | 硬件芯片(Display Controller),负责将多个图层物理叠加。 |
3. BufferQueue 与 Triple Buffering
3.1 Buffer 的生命周期(Ring Buffer)
BufferQueue 中的每个 Buffer 都经历以下状态流转:
#mermaid-svg-kGZA0p6rWHmESaVO{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-kGZA0p6rWHmESaVO .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-kGZA0p6rWHmESaVO .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-kGZA0p6rWHmESaVO .error-icon{fill:#552222;}#mermaid-svg-kGZA0p6rWHmESaVO .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-kGZA0p6rWHmESaVO .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-kGZA0p6rWHmESaVO .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-kGZA0p6rWHmESaVO .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-kGZA0p6rWHmESaVO .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-kGZA0p6rWHmESaVO .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-kGZA0p6rWHmESaVO .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-kGZA0p6rWHmESaVO .marker{fill:#333333;stroke:#333333;}#mermaid-svg-kGZA0p6rWHmESaVO .marker.cross{stroke:#333333;}#mermaid-svg-kGZA0p6rWHmESaVO svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-kGZA0p6rWHmESaVO p{margin:0;}#mermaid-svg-kGZA0p6rWHmESaVO defs #statediagram-barbEnd{fill:#333333;stroke:#333333;}#mermaid-svg-kGZA0p6rWHmESaVO g.stateGroup text{fill:#9370DB;stroke:none;font-size:10px;}#mermaid-svg-kGZA0p6rWHmESaVO g.stateGroup text{fill:#333;stroke:none;font-size:10px;}#mermaid-svg-kGZA0p6rWHmESaVO g.stateGroup .state-title{font-weight:bolder;fill:#131300;}#mermaid-svg-kGZA0p6rWHmESaVO g.stateGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-kGZA0p6rWHmESaVO g.stateGroup line{stroke:#333333;stroke-width:1;}#mermaid-svg-kGZA0p6rWHmESaVO .transition{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-kGZA0p6rWHmESaVO .stateGroup .composit{fill:white;border-bottom:1px;}#mermaid-svg-kGZA0p6rWHmESaVO .stateGroup .alt-composit{fill:#e0e0e0;border-bottom:1px;}#mermaid-svg-kGZA0p6rWHmESaVO .state-note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-kGZA0p6rWHmESaVO .state-note text{fill:black;stroke:none;font-size:10px;}#mermaid-svg-kGZA0p6rWHmESaVO .stateLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-kGZA0p6rWHmESaVO .edgeLabel .label rect{fill:#ECECFF;opacity:0.5;}#mermaid-svg-kGZA0p6rWHmESaVO .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-kGZA0p6rWHmESaVO .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-kGZA0p6rWHmESaVO .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-kGZA0p6rWHmESaVO .edgeLabel .label text{fill:#333;}#mermaid-svg-kGZA0p6rWHmESaVO .label div .edgeLabel{color:#333;}#mermaid-svg-kGZA0p6rWHmESaVO .stateLabel text{fill:#131300;font-size:10px;font-weight:bold;}#mermaid-svg-kGZA0p6rWHmESaVO .node circle.state-start{fill:#333333;stroke:#333333;}#mermaid-svg-kGZA0p6rWHmESaVO .node .fork-join{fill:#333333;stroke:#333333;}#mermaid-svg-kGZA0p6rWHmESaVO .node circle.state-end{fill:#9370DB;stroke:white;stroke-width:1.5;}#mermaid-svg-kGZA0p6rWHmESaVO .end-state-inner{fill:white;stroke-width:1.5;}#mermaid-svg-kGZA0p6rWHmESaVO .node rect{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-kGZA0p6rWHmESaVO .node polygon{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-kGZA0p6rWHmESaVO #statediagram-barbEnd{fill:#333333;}#mermaid-svg-kGZA0p6rWHmESaVO .statediagram-cluster rect{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-kGZA0p6rWHmESaVO .cluster-label,#mermaid-svg-kGZA0p6rWHmESaVO .nodeLabel{color:#131300;}#mermaid-svg-kGZA0p6rWHmESaVO .statediagram-cluster rect.outer{rx:5px;ry:5px;}#mermaid-svg-kGZA0p6rWHmESaVO .statediagram-state .divider{stroke:#9370DB;}#mermaid-svg-kGZA0p6rWHmESaVO .statediagram-state .title-state{rx:5px;ry:5px;}#mermaid-svg-kGZA0p6rWHmESaVO .statediagram-cluster.statediagram-cluster .inner{fill:white;}#mermaid-svg-kGZA0p6rWHmESaVO .statediagram-cluster.statediagram-cluster-alt .inner{fill:#f0f0f0;}#mermaid-svg-kGZA0p6rWHmESaVO .statediagram-cluster .inner{rx:0;ry:0;}#mermaid-svg-kGZA0p6rWHmESaVO .statediagram-state rect.basic{rx:5px;ry:5px;}#mermaid-svg-kGZA0p6rWHmESaVO .statediagram-state rect.divider{stroke-dasharray:10,10;fill:#f0f0f0;}#mermaid-svg-kGZA0p6rWHmESaVO .note-edge{stroke-dasharray:5;}#mermaid-svg-kGZA0p6rWHmESaVO .statediagram-note rect{fill:#fff5ad;stroke:#aaaa33;stroke-width:1px;rx:0;ry:0;}#mermaid-svg-kGZA0p6rWHmESaVO .statediagram-note rect{fill:#fff5ad;stroke:#aaaa33;stroke-width:1px;rx:0;ry:0;}#mermaid-svg-kGZA0p6rWHmESaVO .statediagram-note text{fill:black;}#mermaid-svg-kGZA0p6rWHmESaVO .statediagram-note .nodeLabel{color:black;}#mermaid-svg-kGZA0p6rWHmESaVO .statediagram .edgeLabel{color:red;}#mermaid-svg-kGZA0p6rWHmESaVO #dependencyStart,#mermaid-svg-kGZA0p6rWHmESaVO #dependencyEnd{fill:#333333;stroke:#333333;stroke-width:1;}#mermaid-svg-kGZA0p6rWHmESaVO .statediagramTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-kGZA0p6rWHmESaVO :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 初始化
dequeueBuffer() (App 申请)
queueBuffer() (App 提交)
acquireBuffer() (SF 获取)
releaseBuffer() (SF 释放)
Free
Dequeued
Queued
Acquired
学术定义:
- Free: 空闲状态,可被申请。
- Dequeued: 已被应用申请,正在填充数据。
- Queued: 数据填充完毕,等待 SurfaceFlinger 消费。
- Acquired: 已被 SurfaceFlinger 获取,正在合成。
3.2 Triple Buffering(三重缓冲)
为什么需要 3 个 Buffer?
| 缓冲数量 | 场景 | 结果 |
|---|---|---|
| Single Buffering | 只有 1 个 Buffer | 屏幕正在读时,App 不能写,导致卡顿。 |
| Double Buffering | 2 个 Buffer (Front/Back) | 理想情况流畅,但如果 App 渲染慢于 VSYNC,会导致 Jank(掉帧)。 |
| Triple Buffering | 3 个 Buffer | App 即使慢一帧,也有第三个 Buffer 可以准备下一帧,极大减少 Jank。 |
#mermaid-svg-5sib2a7ZXRCPWT3m{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-5sib2a7ZXRCPWT3m .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-5sib2a7ZXRCPWT3m .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-5sib2a7ZXRCPWT3m .error-icon{fill:#552222;}#mermaid-svg-5sib2a7ZXRCPWT3m .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-5sib2a7ZXRCPWT3m .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-5sib2a7ZXRCPWT3m .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-5sib2a7ZXRCPWT3m .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-5sib2a7ZXRCPWT3m .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-5sib2a7ZXRCPWT3m .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-5sib2a7ZXRCPWT3m .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-5sib2a7ZXRCPWT3m .marker{fill:#333333;stroke:#333333;}#mermaid-svg-5sib2a7ZXRCPWT3m .marker.cross{stroke:#333333;}#mermaid-svg-5sib2a7ZXRCPWT3m svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-5sib2a7ZXRCPWT3m p{margin:0;}#mermaid-svg-5sib2a7ZXRCPWT3m .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-5sib2a7ZXRCPWT3m .cluster-label text{fill:#333;}#mermaid-svg-5sib2a7ZXRCPWT3m .cluster-label span{color:#333;}#mermaid-svg-5sib2a7ZXRCPWT3m .cluster-label span p{background-color:transparent;}#mermaid-svg-5sib2a7ZXRCPWT3m .label text,#mermaid-svg-5sib2a7ZXRCPWT3m span{fill:#333;color:#333;}#mermaid-svg-5sib2a7ZXRCPWT3m .node rect,#mermaid-svg-5sib2a7ZXRCPWT3m .node circle,#mermaid-svg-5sib2a7ZXRCPWT3m .node ellipse,#mermaid-svg-5sib2a7ZXRCPWT3m .node polygon,#mermaid-svg-5sib2a7ZXRCPWT3m .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-5sib2a7ZXRCPWT3m .rough-node .label text,#mermaid-svg-5sib2a7ZXRCPWT3m .node .label text,#mermaid-svg-5sib2a7ZXRCPWT3m .image-shape .label,#mermaid-svg-5sib2a7ZXRCPWT3m .icon-shape .label{text-anchor:middle;}#mermaid-svg-5sib2a7ZXRCPWT3m .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-5sib2a7ZXRCPWT3m .rough-node .label,#mermaid-svg-5sib2a7ZXRCPWT3m .node .label,#mermaid-svg-5sib2a7ZXRCPWT3m .image-shape .label,#mermaid-svg-5sib2a7ZXRCPWT3m .icon-shape .label{text-align:center;}#mermaid-svg-5sib2a7ZXRCPWT3m .node.clickable{cursor:pointer;}#mermaid-svg-5sib2a7ZXRCPWT3m .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-5sib2a7ZXRCPWT3m .arrowheadPath{fill:#333333;}#mermaid-svg-5sib2a7ZXRCPWT3m .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-5sib2a7ZXRCPWT3m .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-5sib2a7ZXRCPWT3m .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-5sib2a7ZXRCPWT3m .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-5sib2a7ZXRCPWT3m .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-5sib2a7ZXRCPWT3m .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-5sib2a7ZXRCPWT3m .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-5sib2a7ZXRCPWT3m .cluster text{fill:#333;}#mermaid-svg-5sib2a7ZXRCPWT3m .cluster span{color:#333;}#mermaid-svg-5sib2a7ZXRCPWT3m div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-5sib2a7ZXRCPWT3m .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-5sib2a7ZXRCPWT3m rect.text{fill:none;stroke-width:0;}#mermaid-svg-5sib2a7ZXRCPWT3m .icon-shape,#mermaid-svg-5sib2a7ZXRCPWT3m .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-5sib2a7ZXRCPWT3m .icon-shape p,#mermaid-svg-5sib2a7ZXRCPWT3m .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-5sib2a7ZXRCPWT3m .icon-shape .label rect,#mermaid-svg-5sib2a7ZXRCPWT3m .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-5sib2a7ZXRCPWT3m .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-5sib2a7ZXRCPWT3m .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-5sib2a7ZXRCPWT3m :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 三缓冲 (抗抖动)
显示
渲染
显示
渲染
显示
渲染
VSYNC 1
Buffer A
Buffer B
VSYNC 2
Buffer C
VSYNC 3
双缓冲 (容易卡顿)
显示
渲染
显示
等待
VSYNC 1
Front Buffer
Back Buffer
VSYNC 2
4. VSYNC 信号机制
4.1 VSYNC 的产生与分发
VSYNC 是图形系统的节拍器。
Choreographer 应用进程 Choreographer SurfaceFlinger DispSync (软件模型) 硬件 (Display) Choreographer 应用进程 Choreographer SurfaceFlinger DispSync (软件模型) 硬件 (Display) #mermaid-svg-YRY4EaGsjihjmpr0{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-YRY4EaGsjihjmpr0 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-YRY4EaGsjihjmpr0 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-YRY4EaGsjihjmpr0 .error-icon{fill:#552222;}#mermaid-svg-YRY4EaGsjihjmpr0 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-YRY4EaGsjihjmpr0 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-YRY4EaGsjihjmpr0 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-YRY4EaGsjihjmpr0 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-YRY4EaGsjihjmpr0 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-YRY4EaGsjihjmpr0 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-YRY4EaGsjihjmpr0 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-YRY4EaGsjihjmpr0 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-YRY4EaGsjihjmpr0 .marker.cross{stroke:#333333;}#mermaid-svg-YRY4EaGsjihjmpr0 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-YRY4EaGsjihjmpr0 p{margin:0;}#mermaid-svg-YRY4EaGsjihjmpr0 .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-YRY4EaGsjihjmpr0 text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-YRY4EaGsjihjmpr0 .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-YRY4EaGsjihjmpr0 .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-YRY4EaGsjihjmpr0 .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-YRY4EaGsjihjmpr0 .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-YRY4EaGsjihjmpr0 #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-YRY4EaGsjihjmpr0 .sequenceNumber{fill:white;}#mermaid-svg-YRY4EaGsjihjmpr0 #sequencenumber{fill:#333;}#mermaid-svg-YRY4EaGsjihjmpr0 #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-YRY4EaGsjihjmpr0 .messageText{fill:#333;stroke:none;}#mermaid-svg-YRY4EaGsjihjmpr0 .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-YRY4EaGsjihjmpr0 .labelText,#mermaid-svg-YRY4EaGsjihjmpr0 .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-YRY4EaGsjihjmpr0 .loopText,#mermaid-svg-YRY4EaGsjihjmpr0 .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-YRY4EaGsjihjmpr0 .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-YRY4EaGsjihjmpr0 .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-YRY4EaGsjihjmpr0 .noteText,#mermaid-svg-YRY4EaGsjihjmpr0 .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-YRY4EaGsjihjmpr0 .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-YRY4EaGsjihjmpr0 .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-YRY4EaGsjihjmpr0 .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-YRY4EaGsjihjmpr0 .actorPopupMenu{position:absolute;}#mermaid-svg-YRY4EaGsjihjmpr0 .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-YRY4EaGsjihjmpr0 .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-YRY4EaGsjihjmpr0 .actor-man circle,#mermaid-svg-YRY4EaGsjihjmpr0 line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-YRY4EaGsjihjmpr0 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} par分发至合成器分发至应用 硬件 VSYNC 脉冲 (60Hz)校准相位 (Phase Offset)Signal (SF VSYNC)开始合成 (doComposition)Signal (App VSYNC)doFrame()执行 Input/Animation/TraversalqueueBuffer()
学术定义:
- HW VSYNC: 显示器硬件产生的物理信号。
- SW VSYNC (DispSync): Android 在软件层模拟的 VSYNC,用于同步 HWComposer。
- Phase Offset (相位偏移): 为了让 App 的渲染和 SF 的合成错开,避免同时抢占 CPU/GPU 资源。
4.2 Choreographer(编舞者)
Choreographer 运行在应用进程 的主线程,它是 VSYNC 信号的接收者。
源码解析:
java
// Choreographer.java
void doFrame(long frameTimeNanos, int frame) {
// 1. 处理输入事件
doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);
// 2. 执行动画
doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
// 3. 执行 Traversal (measure/layout/draw)
doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
// 4. 提交帧
doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos);
}
5. SurfaceFlinger 的合成算法
5.1 合成策略:Client Composition vs Device Composition
SurfaceFlinger 面临一个选择:是用 GPU 合成,还是用硬件叠加?
| 合成方式 | 执行者 | 适用场景 | 性能 |
|---|---|---|---|
| Device Composition (HWC) | 硬件叠加器 (Display Controller) | 不透明图层、无复杂变换 | 极高 (零拷贝) |
| Client Composition (GPU) | GPU (OpenGL ES) | 透明图层、复杂变换、旋转 | 较低 (需要渲染) |
5.2 HWC (Hardware Composer) 的工作流程
HWC 是 SurfaceFlinger 的"硬件助手"。
#mermaid-svg-nsWJr70YFblLz5kn{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-nsWJr70YFblLz5kn .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-nsWJr70YFblLz5kn .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-nsWJr70YFblLz5kn .error-icon{fill:#552222;}#mermaid-svg-nsWJr70YFblLz5kn .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-nsWJr70YFblLz5kn .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-nsWJr70YFblLz5kn .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-nsWJr70YFblLz5kn .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-nsWJr70YFblLz5kn .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-nsWJr70YFblLz5kn .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-nsWJr70YFblLz5kn .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-nsWJr70YFblLz5kn .marker{fill:#333333;stroke:#333333;}#mermaid-svg-nsWJr70YFblLz5kn .marker.cross{stroke:#333333;}#mermaid-svg-nsWJr70YFblLz5kn svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-nsWJr70YFblLz5kn p{margin:0;}#mermaid-svg-nsWJr70YFblLz5kn .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-nsWJr70YFblLz5kn .cluster-label text{fill:#333;}#mermaid-svg-nsWJr70YFblLz5kn .cluster-label span{color:#333;}#mermaid-svg-nsWJr70YFblLz5kn .cluster-label span p{background-color:transparent;}#mermaid-svg-nsWJr70YFblLz5kn .label text,#mermaid-svg-nsWJr70YFblLz5kn span{fill:#333;color:#333;}#mermaid-svg-nsWJr70YFblLz5kn .node rect,#mermaid-svg-nsWJr70YFblLz5kn .node circle,#mermaid-svg-nsWJr70YFblLz5kn .node ellipse,#mermaid-svg-nsWJr70YFblLz5kn .node polygon,#mermaid-svg-nsWJr70YFblLz5kn .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-nsWJr70YFblLz5kn .rough-node .label text,#mermaid-svg-nsWJr70YFblLz5kn .node .label text,#mermaid-svg-nsWJr70YFblLz5kn .image-shape .label,#mermaid-svg-nsWJr70YFblLz5kn .icon-shape .label{text-anchor:middle;}#mermaid-svg-nsWJr70YFblLz5kn .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-nsWJr70YFblLz5kn .rough-node .label,#mermaid-svg-nsWJr70YFblLz5kn .node .label,#mermaid-svg-nsWJr70YFblLz5kn .image-shape .label,#mermaid-svg-nsWJr70YFblLz5kn .icon-shape .label{text-align:center;}#mermaid-svg-nsWJr70YFblLz5kn .node.clickable{cursor:pointer;}#mermaid-svg-nsWJr70YFblLz5kn .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-nsWJr70YFblLz5kn .arrowheadPath{fill:#333333;}#mermaid-svg-nsWJr70YFblLz5kn .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-nsWJr70YFblLz5kn .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-nsWJr70YFblLz5kn .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-nsWJr70YFblLz5kn .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-nsWJr70YFblLz5kn .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-nsWJr70YFblLz5kn .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-nsWJr70YFblLz5kn .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-nsWJr70YFblLz5kn .cluster text{fill:#333;}#mermaid-svg-nsWJr70YFblLz5kn .cluster span{color:#333;}#mermaid-svg-nsWJr70YFblLz5kn div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-nsWJr70YFblLz5kn .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-nsWJr70YFblLz5kn rect.text{fill:none;stroke-width:0;}#mermaid-svg-nsWJr70YFblLz5kn .icon-shape,#mermaid-svg-nsWJr70YFblLz5kn .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-nsWJr70YFblLz5kn .icon-shape p,#mermaid-svg-nsWJr70YFblLz5kn .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-nsWJr70YFblLz5kn .icon-shape .label rect,#mermaid-svg-nsWJr70YFblLz5kn .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-nsWJr70YFblLz5kn .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-nsWJr70YFblLz5kn .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-nsWJr70YFblLz5kn :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Hardware Composer
SurfaceFlinger
不透明
不透明
半透明
不透明
合成结果
Layer 1 (Status Bar)
Layer 2 (Wallpaper)
Layer 3 (App Window)
Layer 4 (Navigation Bar)
Overlay 1 (Status Bar)
Overlay 2 (Wallpaper)
Overlay 3 (App Window)
Overlay 4 (Nav Bar)
GPU 合成
学术定义:
- Overlay Planes: 硬件支持的物理图层。每个 Plane 可以直接显示一块内存,无需拷贝。
- GPU Fallback: 如果图层太多(超过 HWC 支持的 Overlay 数量)或者有复杂特效,SurfaceFlinger 会强制使用 GPU 将所有图层合成到一个 Buffer 中,再由 HWC 显示。
6. 关键源码解析
6.1 SurfaceFlinger 的主循环
SurfaceFlinger 是一个典型的 Event Loop 模型。
cpp
// frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
void SurfaceFlinger::run() {
while (true) {
waitForEvent(); // 等待 VSYNC 或 Buffer 提交
handleMessageRefresh(); // 处理刷新
}
}
void SurfaceFlinger::handleMessageRefresh() {
preComposition(); // 准备合成
rebuildLayerStacks(); // 重建图层堆栈
setUpHWComposer(); // 配置 HWC
doComposition(); // 执行合成
postComposition(); // 提交到显示
}
6.2 BufferQueue 的核心逻辑
cpp
// frameworks/native/libs/gui/BufferQueueProducer.cpp
status_t BufferQueueProducer::dequeueBuffer(...) {
// 1. 查找 Free Buffer
// 2. 如果没有,等待
// 3. 返回 Buffer 的 Slot
}
status_t BufferQueueProducer::queueBuffer(...) {
// 1. 标记 Buffer 为 Queued
// 2. 通知 Consumer (SurfaceFlinger)
listener->onFrameAvailable();
}
7. 掉帧(Jank)的学术成因
7.1 掉帧的数学模型
假设屏幕刷新率为 60Hz,每帧时间约为 16.67ms。
| 阶段 | 耗时 | 结果 |
|---|---|---|
| App 渲染 | 20ms | 掉帧。超过了 16.67ms,下一帧 VSYNC 到来时还没画完。 |
| SurfaceFlinger 合成 | 10ms | 正常。 |
| HWC 显示 | 1ms | 正常。 |
学术定义:
- Deadline Miss: 未能在 VSYNC 信号到来前完成渲染或合成。
- Buffer Stuffing: 由于 App 太慢,BufferQueue 被填满,App 必须等待 SurfaceFlinger 消费后才能继续渲染。
8. 本篇总结(Knowledge Closure)
| 关键点 | 纯学术定义 |
|---|---|
| SurfaceFlinger 的本质 | 系统级合成服务,负责将多个应用的 Surface 合成为单一帧。 |
| VSYNC 的作用 | 同步软件渲染与硬件刷新的节拍器,防止画面撕裂。 |
| BufferQueue 机制 | 基于 Triple Buffering 的环形缓冲区,解耦生产者与消费者。 |
| HWC 的价值 | 利用硬件叠加器(Overlay)实现零拷贝合成,是流畅度的关键。 |
| Choreographer 的角色 | 应用进程的 VSYNC 接收者,协调 Input、Animation 和 Drawing。 |
下一篇预告 :第三板块:Android 图形渲染与窗口体系 | 第十四篇:View 绘制体系与 RenderThread 异步渲染