这三个名字是 Systrace/Perfetto 里看到的 vsync 信号(VSYNC-app、VSYNC-appSf、VSYNC-sf),它们都在 SurfaceFlinger 进程里,由同一套 vsync 预测和定时机制驱动。区别在于服务的对象和唤醒的时间点不同。
一、总览
| 名称 | 本质 | 服务对象 | 作用 |
|---|---|---|---|
| app | EventThread(线程名 app) | 普通 App 进程的 Choreographer | 唤醒 App 开始画一帧(doFrame) |
| appSf | EventThread(线程名 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 再合成的流水线。