Vsync 信号(VSYNC-app、VSYNC-appSf、VSYNC-sf)简析

1 阅读3分钟

这三个名字是 Systrace/Perfetto 里看到的 vsync 信号(VSYNC-app、VSYNC-appSf、VSYNC-sf),它们都在 SurfaceFlinger 进程里,由同一套 vsync 预测和定时机制驱动。区别在于服务的对象和唤醒的时间点不同。

一、总览

名称本质服务对象作用
appEventThread(线程名 app)普通 App 进程的 Choreographer唤醒 App 开始画一帧(doFrame)
appSfEventThread(线程名 appSf)用 SF vsync 源的客户端,主要是 system_server 里的 Choreographer.getSfInstance()让 WMS 等系统动画的节拍和 SF 对齐
sf不是 EventThread,是 SF 自己 MessageQueue 注册的回调SurfaceFlinger 主线程唤醒 SF 执行 commit 和 composite(合成上屏)

还有一个相关线程叫 TimerDispatch:三个信号的定时器都在这个线程上触发(VSyncDispatchTimerQueue 基于 timerfd 实现)。定时到了以后,它再分发给 app、appSf 线程或 SF 主线程。

二、创建位置(Android 12–14)

SurfaceFlinger::initScheduler():

// app:给普通 App
mAppConnectionHandle = createConnection("app",
        /*workDuration*/  configs.late.appWorkDuration,
        /*readyDuration*/ configs.late.sfWorkDuration);

// appSf:给使用 SF vsync 源的客户端
mSfConnectionHandle = createConnection("appSf",
        /*workDuration*/  vsyncPeriod,
        /*readyDuration*/ configs.late.sfWorkDuration);

// sf:SF 自己
mEventQueue->initVsync(mScheduler->getVsyncDispatch(), ...,
        /*workDuration*/  configs.late.sfWorkDuration);

Android 13 以后改成 createEventThread(Cycle::Render / Cycle::LastComposite, ...),含义不变。

三、唤醒时间点

三者共用 VSyncPredictor 预测出的同一个目标 vsync(记为 V),各自的唤醒时间是:

sf    唤醒 ≈ V − sfWorkDuration
app   唤醒 ≈ V − appWorkDuration − sfWorkDuration
appSf 唤醒 ≈ V − vsyncPeriod − sfWorkDuration     // 相位与 SF 对齐,提前约一帧

所以 App 先被唤醒去画,画完提交 buffer,SurfaceFlinger 在 sf 时间点 latch 这个 buffer 并合成。两者之间的时间差就是 App 可用的绘制预算。

四、各自的分发路径

app

App: Choreographer.scheduleVsync → DisplayEventReceiver.requestNextVsync
  → SF: EventThread(app) → VSyncCallbackRegistration.schedule
TimerDispatch 定时到 → EventThread(app) 被唤醒
  → 通过 BitTube(socket)发 vsync 事件给 App
  → App 主线程 onVsync → doFrame

appSf

system_server: Choreographer.getSfInstance()   // VSYNC_SOURCE_SURFACE_FLINGER
  使用者:SurfaceAnimationRunner、WindowAnimator 等 WMS 动画
→ 连接的是 EventThread(appSf),分发路径和 app 一样

appSf 的意义:WMS 动画改的是 leash 的 Transaction(位置、透明度等),不经过 App 绘制。它的节拍跟 SF 的相位对齐,这样每帧提交的 Transaction 都能赶上同一次合成,动画不容易出现跳帧或抖动。

sf

SF 收到 Transaction/buffer → scheduleCommit() → MessageQueue::scheduleFrame()
TimerDispatch 定时到 → MessageQueue::vsyncCallback
  → 投递到 SF 主线程 → commit(latch buffer、应用 Transaction)
                     → composite(HWC/GPU 合成)→ present

五、Trace 里怎么看

  • VSYNC-app / VSYNC-appSf / VSYNC-sf 计数器:每触发一次就在 0 和 1 之间翻转一次。
    • 不翻转说明那段时间没有人申请(按需触发)。
    • 翻转很密说明一直有人在申请,比如持续的动画。
  • HW_VSYNC:硬件 vsync 采样。只在 predictor 需要重新校准时才打开,平时是关闭的。
  • app / appSf 线程:看它们什么时候被唤醒、往哪些连接发送了事件。
  • TimerDispatch 线程:看定时器触发的时间是否准确。

调试命令:adb shell dumpsys SurfaceFlinger --vsync(新版本),或者直接 dumpsys SurfaceFlinger,然后查看 VsyncConfiguration、各 EventThread 的连接列表和 duration。

一句话总结:app 叫醒普通 App 画帧,appSf 叫醒系统动画(相位与 SF 对齐),sf 叫醒 SF 合成。三者共用一个预测器,靠不同的 duration 错开唤醒时间,形成 App 先画、SF 再合成的流水线。