Android VSync 笔记

关于VSync的产生,你需要彻底更新一个认知:Android系统里你看到的那些整齐的VSYNC-APP和VSYNC-SF信号,99%的时间里并不是硬件直接产生的,而是SurfaceFlinger用数学公式"算"出来的。

为了把这个"算出来"的过程讲透,我们从物理源头软件衍生按需开关三个层面逐步拆解。


一、物理源头:硬件VSync的"原始脉搏"

VSync这个概念的诞生比Android早几十年,它源自CRT显示器电子枪的物理动作。

1.1 它最初是显示器"喘口气"的信号

  • 电子枪从左到右、从上到下扫描屏幕,扫完一帧后必须关闭电子束、从右下角瞬间移回左上角(垂直回扫)。
  • 这段短暂的"空窗期"会触发一个脉冲------垂直同步信号(VSync),告诉显卡:"上一帧已显示完毕,可以送下一帧了"。
  • 现代LCD虽无电子枪,但为了兼容,显示控制器(Display Controller)会模拟这个时序,通过硬件定时器产生固定频率的脉冲。这个频率就是屏幕刷新率(60Hz/90Hz/120Hz等)。

1.2 Android里谁在制造这个原始脉冲? Hardware Composer(HWC) 。它是显示驱动的一部分,直接与硬件定时器交互。每当屏幕完成一次刷新,HWC就通过回调向SurfaceFlinger发送一个HW_VSYNC_0信号。

关键认知 :这个硬件信号极其"原始"------它只是一串准确但没有任何业务逻辑的时间戳。它不知道谁是App、谁是SurfaceFlinger,只会每分钟60次(或更高)忠实地发出脉冲。


二、软件衍生:DispSync的"神算局"

如果让App和SurfaceFlinger每次都直接响应HW_VSYNC_0,会有两个严重问题:

  1. 功耗灾难:即使屏幕静止不动(如看电子书),App和SF也会每16.6ms被唤醒,疯狂空转。
  2. 相位死锁 :App绘制、SF合成、屏幕显示三者挤在同一个时间点开工,流水线严重阻塞(旧Android版本的痛点)。

于是Android 4.1(Project Butter)引入了DispSync模块 ------一个基于数学预测的软件VSync生成器。这是整个机制最精妙的部分。

2.1 DispSync的工作原理:锁相环的软件实现

DispSync本质上是一个数字锁相环(Digital Phase-Locked Loop) 。它不依赖硬件中断实时触发,而是通过采样硬件VSync的历史时间,拟合出一条精准的"虚拟时钟线"

第一步:采样与建模

  • SurfaceFlinger会持续接收HW_VSYNC_0信号,但并不立刻分发
  • DispSync收集至少3个、最多32个 硬件VSync时间戳,通过最小二乘法或均值滤波计算出平均周期(AvgPeriod)平均相位(AvgPhase)
  • 数学公式(简化版):
    • 将每个时间戳映射到单位圆角度:ΔPhase = 2π * (timestamp % AvgPeriod) / AvgPeriod
    • 计算所有采样点的平均向量 (AvgX, AvgY)
    • SW_VSYNC相位 = atan2(AvgY, AvgX)
    • 最终:SW_VSYNC时间 = AvgPeriod + AvgPhase

一旦模型误差收敛(通常6个采样后),DispSync会立即关闭硬件VSync中断**,完全靠这套数学模型产生后续的软件VSync。这就是"用计算代替中断"的核心节能设计。

2.2 一源双生:VSYNC-APP与VSYNC-SF

硬件只提供一个原始脉冲,但系统需要两个不同用途的节拍器。DispSync在生成软件VSync时,会直接产出两条相位偏移的时钟流

ini 复制代码
VSYNC-APP = SW_VSYNC基准 + phase_app偏移量
VSYNC-SF  = SW_VSYNC基准 + phase_sf偏移量
  • phase_app:通常为0~2ms(应用先开始绘制)
  • phase_sf:通常为4~6ms(SF稍后开始合成,刚好等App画完)

这两条信号就是你在Systrace里看到的彩色VSync条。它们的周期完全一致(16.6ms) ,但起始时间错开,形成流水线。

对比总结(纠正常见误区):

信号名称 产生者 是否硬件直接发出 用途 触发方式
HW_VSYNC_0 HWC/显示控制器 ✅ 是 校准DispSync模型 硬件定时器,固定频率
VSYNC-APP DispSync(软件) ❌ 否 触发Choreographer开始绘制 按需 + 模型预测
VSYNC-SF DispSync(软件) ❌ 否 触发SurfaceFlinger合成 按需 + 模型预测

三、按需触发:没有绘制任务时,VSync去哪了?

这是Android VSync机制最容易误解的地方:Systrace里VSync-APP/SF信号并非每16.6ms都有。它们的出现遵循**按需申请(requestNextVsync)**原则。

3.1 为什么必须按需? 假设你打开一个静态文本页面:

  • 屏幕内容完全没有变化。
  • 如果DispSync仍然每16.6ms向App发送VSYNC-APP,App的主线程会持续每帧执行doFrame(),空转测量布局绘制------CPU空耗、发热、掉电。
  • 完全没必要

3.2 申请-触发机制

  • App侧 :只有当Choreographer.postCallback()被调用(如View.invalidate()、动画启动),才会通过Binder向SF的EventThread请求下一个VSYNC-APP
  • SF侧 :只有当BufferQueue中有新Buffer入队,或者窗口状态变化,才会请求下一个VSYNC-SF
  • DispSync侧 :只有当至少一个客户端在等待 时,它才会在预测的时钟点上发射软件VSync;如果无人申请,DispSync保持静默,整个图形系统进入低功耗状态。

这就是为什么Systrace里VSync信号时疏时密------动态场景(滑动、动画)密集出现;静态场景几乎消失。

3.3 硬件VSync的重校准 当DispSync长期依靠软件预测,可能会因温漂、时钟偏差而产生相位误差。如何修正?

  • SurfaceFlinger在postComposition()时会检查Present Fence(帧实际显示的时间戳)。
  • 将这些Fence时间与SW_VSYNC预测时间对比,计算误差平方和
  • 若误差超过阈值(如1.5ms),DispSync会临时重新使能硬件VSync,采集3~6个新样本重新建模,然后再次关闭硬件VSync。

这是一套完整的闭环自适应系统:硬件提供基准,软件负责分发,误差触发校准。


四、全景流程图(建议收藏)

flowchart TD A[显示控制器硬件定时器] -->|固定频率脉冲| B[HWC产生HW_VSYNC_0] B --> C{SurfaceFlinger DispSync} C -->|采样至少3个时间戳| D[计算平均周期与相位] D -->|模型收敛| E[关闭硬件VSync中断] E --> F[软件预测生成SW_VSYNC基准时钟] F -->|+ phase_app偏移| G[VSYNC-APP] F -->|+ phase_sf偏移| H[VSYNC-SF] G -->|按需:App调用requestNextVsync| I[触发Choreographer绘制] H -->|按需:SF有Buffer待合成| J[触发SurfaceFlinger合成] I --> K[GPU渲染完成] K --> L[Buffer入队] L -->|触发SF申请下一帧VSYNC-SF| J J --> M[合成送显] M -->|检查Present Fence误差| N{误差超阈值?} N -->|是| O[临时开启硬件VSync] O -->|重新采样| C N -->|否| P[保持软件预测模式]

五、回答你最初的问题:"VSync是如何产生的?"

分三个层次回答:

  1. 物理层:显示控制器硬件定时器每16.6ms产生一个脉冲,HWC捕获后作为HW_VSYNC_0上报。
  2. 软件层 :SurfaceFlinger的DispSync模块将硬件信号作为"校准样本",通过锁相环算法拟合出一条持续运行的虚拟时钟线 ,并在这根时钟线上同时开出两条相位错开的信号通道(VSYNC-APP/VSYNC-SF)。
  3. 策略层 :这两条软件信号并非周期性自动发射 ,而是严格遵循按需申请机制------只有App或SF明确"我需要下一帧",DispSync才在预测时间点发射信号。

所以,VSync的最终形态------你在Systrace里看到的那些彩色节拍------是"硬件定时校准 + 软件预测生成 + 按需触发"三者结合的产物。 它不是纯粹的硬件中断,也不是纯粹的操作系统时钟,而是Android为移动场景定制的自适应、低功耗同步引擎

相关推荐
城东米粉儿2 小时前
Android SurfaceFlinger 笔记
android
似霰2 小时前
Android 日志系统5——logd 写日志过程分析二
android·log
hewence12 小时前
Kotlin CoroutineContext 详解
android·开发语言·kotlin
Albert Edison2 小时前
【Python】文件
android·服务器·python
大模型玩家七七3 小时前
效果评估:如何判断一个祝福 AI 是否“走心”
android·java·开发语言·网络·人工智能·batch
Aurora4193 小时前
Android事件分发逻辑--针对事件分发相关函数的讲解
android
似霰3 小时前
Android 日志系统4——logd 写日志过程分析一
android
youyoulg4 小时前
利用Android Studio编译Android上可直接执行的二进制
android·ide·android studio