第三板块:Android 图形渲染与窗口体系 | 第十三篇:SurfaceFlinger 与 VSYNC 信号机制

第三板块: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 异步渲染

相关推荐
Che2n3JigW1 小时前
Now in Android:它不是最佳实践,而是大型 Android 工程实践的展示
android·architecture·now in android
Che2n3JigW2 小时前
Now in Android Feature 模块分析:一个功能是如何被组织起来的?
android·udf·architecture·now in android·modularization·feature module
Che2n3JigW2 小时前
Now in Android 项目结构分析:这个 App 是如何搭建起来的?
android·architecture·now in android·modularization·structure
恋猫de小郭2 小时前
flutter_agent_lens 用 MCP 服务,将 Flutter DevTools 暴露给 AI
android·前端·flutter
AI玫瑰助手2 小时前
Python函数:内置函数(len/max/min/sorted等)详解
android·开发语言·python
Kapaseker2 小时前
Kotlin 集合:只读不等于不可变
android·kotlin
风华圆舞2 小时前
一个 Flutter 项目同时保留 Android、iOS、HarmonyOS 支持的实践
android·flutter·ios
顾林海2 小时前
Android来时路:Android 是什么
android
2501_915921432 小时前
uni-app 上架 iOS 的完整流程(无需依赖 Mac)
android·macos·ios·小程序·uni-app·iphone·webview