引言
在前两篇文章中,我们深入分析了SurfaceFlinger的核心机制和图形缓冲区管理。本文将继续探讨Android显示系统中最关键的同步机制——Vsync(垂直同步),以及如何基于Vsync构建流畅的用户体验。
Vsync是Android显示系统的"心跳",它像一个精准的节拍器,协调着应用绘制、系统合成、屏幕显示三个环节的完美配合。理解Vsync机制,是掌握Android性能优化的关键。
本文将基于Android 15 (AOSP)实际源码,深入分析以下核心内容:
- Vsync信号的产生与分发机制
- Choreographer如何协调应用侧渲染
- 三重缓冲如何减少掉帧
- 使用Systrace/Perfetto诊断性能问题的完整实战
系列导航: 这是"Android 15 核心子系统深度解析"系列的第3篇文章。建议先阅读前两篇了解显示系统基础。
一、Vsync垂直同步机制
1.1 Vsync的作用
在传统的CRT显示器时代,电子枪从屏幕左上角开始,逐行扫描到右下角,完成一帧画面的显示。当电子枪回到起点准备下一帧时,会发出一个"垂直同步信号"(Vsync),告诉系统"现在可以安全地更新帧缓冲了"。
虽然现代LCD/OLED显示器没有电子枪,但Vsync的概念被完整保留下来,成为同步渲染管线的关键机制。
Vsync解决的核心问题:
画面撕裂(Screen Tearing)
- 问题:GPU渲染速度快于Display刷新,导致一帧画面显示了上下两个不同的内容
- 解决:Vsync确保GPU渲染和Display刷新同步进行
资源浪费
- 问题:GPU盲目高速渲染,浪费CPU/GPU资源和电量
- 解决:Vsync让渲染按需进行,每个Vsync周期最多渲染一帧
流程协调
- 问题:应用绘制、SurfaceFlinger合成、Display显示三个环节需要精确配合
- 解决:Vsync作为全局时钟,协调三者的工作节奏
1.2 Vsync信号的产生
Android 15的Vsync信号有两个来源:硬件Vsync和软件Vsync。
硬件Vsync
硬件Vsync的产生路径:
Display Driver → HWC (IComposerCallback::onVsync) → SurfaceFlinger → VSyncReactor → VsyncSchedule硬件Vsync是Display Driver在每次完成一帧扫描后发出的真实信号,通过HWC 3.0的回调接口上报给SurfaceFlinger。
让我们看看HWC回调的源码(位于hardware/interfaces/graphics/composer/aidl/android/hardware/graphics/composer3/IComposerCallback.aidl):
interfaceIComposerCallback{/** * 硬件Vsync回调 * @param display 发生Vsync的显示设备ID * @param timestamp Vsync时间戳(纳秒) * @param vsyncPeriodNanos Vsync周期(纳秒) */onewayvoidonVsync(longdisplay,longtimestamp,intvsyncPeriodNanos);/** * 热插拔回调 */onewayvoidonHotplug(longdisplay,booleanconnected);/** * 刷新率改变回调 */onewayvoidonRefresh(longdisplay);}软件Vsync
硬件Vsync虽然准确,但频繁的中断会带来性能开销。Android采用了一种聪明的优化策略:
- 初始阶段: 使用硬件Vsync采样,建立Vsync模型
- 稳定阶段: 关闭硬件Vsync,使用VSyncPredictor基于历史数据预测下一次Vsync
- 校准阶段: 定期使用硬件Vsync校准预测模型
这种混合策略兼顾了准确性和性能。
VSyncPredictor的核心逻辑(源码位于frameworks/native/services/surfaceflinger/Scheduler/VSyncPredictor.cpp):
classVSyncPredictor:publicVsyncTracker{// 历史Vsync时间戳队列std::deque<nsecs_t>mTimestamps;// 预测下一次Vsync时间nsecs_tnextAnticipatedVSyncTimeFrom(nsecs_t timePoint){// 基于历史数据计算Vsync周期constautoperiod=currentPeriod();// 找到timePoint之后最近的Vsync时刻returntimePoint+period-(timePoint%period);}// 添加硬件Vsync采样,校准模型voidaddVsyncTimestamp(nsecs_t timestamp){mTimestamps.push_back(timestamp);// 保留最近N个样本(通常20个)if(mTimestamps.size()>mHistorySize){mTimestamps.pop_front();}// 重新计算周期(去除异常值)recalculatePeriod();}};1.3 Vsync分发机制
SurfaceFlinger收到Vsync信号后,需要分发给两类消费者:应用进程和SurfaceFlinger自己。但这两者的需求不同:
- 应用进程: 需要提前收到Vsync,以便有足够时间绘制(通常提前2ms)
- SurfaceFlinger: 准时收到Vsync,立即开始合成
这就是Vsync Phase Offset(相位偏移)机制。
EventThread: App-Vsync vs SF-Vsync
Android维护了两个EventThread:
// frameworks/native/services/surfaceflinger/SurfaceFlinger.cppvoidSurfaceFlinger::init(){// 创建app-vsync的EventThread,带-2ms offsetmAppConnectionHandle=mScheduler->createConnection("app",mFrameTimeline->getTokenManager(),/* workDuration */configs.late.appWorkDuration,/* readyDuration */configs.late.sfWorkDuration);// 创建sf-vsync的EventThread,0ms offsetmSfConnectionHandle=mScheduler->createConnection("sf",mFrameTimeline->getTokenManager(),/* workDuration */configs.late.sfWorkDuration,/* readyDuration */Duration::fromNs(0));}时序关系:
真实Vsync时刻: T0 ↓ App-Vsync触发: T0 - 2ms (提前触发) ↓ (应用有2ms时间开始绘制) 真实Vsync到达: T0 ↓ SF-Vsync触发: T0 (准时触发) ↓ SurfaceFlinger开始合成这个2ms的提前量是可配置的,取决于设备性能和屏幕刷新率。
EventThread源码分析
EventThread负责接收Vsync信号并分发给注册的消费者(源码位于frameworks/native/services/surfaceflinger/Scheduler/EventThread.h):
classEventThread{public:// 创建EventConnection供应用连接virtualsp<EventThreadConnection>createEventConnection(EventRegistrationFlags eventRegistration={})const=0;// Vsync回调,由VsyncSchedule触发voidonVsync(nsecs_t vsyncTime,nsecs_t wakeupTime,nsecs_t readyTime);private:// 线程主循环voidthreadMain(){while(true){// 等待Vsync信号waitForVsyncSignal();// 分发给所有注册的ConnectiondispatchVsyncEvent();}}// 已注册的连接列表std::vector<sp<EventThreadConnection>>mConnections;};应用通过DisplayEventReceiver连接到EventThread:
// 应用侧代码(Choreographer内部)mDisplayEventReceiver=newDisplayEventReceiver(Looper.myLooper(),vsyncSource,configChanged);关键要点:
- 硬件Vsync准确但开销大,软件Vsync预测效率高
- Phase Offset让应用提前收到Vsync,有更多时间绘制
- EventThread是Vsync分发的中枢,维护所有消费者连接
1.4 Android 15的Vsync优化
Android 15在Vsync机制上进行了多项优化:
1. 动态刷新率支持(Variable Refresh Rate)
Android 15支持根据内容动态调整刷新率:
- 静态内容: 降低到30Hz或更低,节省电量
- 动画/视频: 提升到90Hz/120Hz,保证流畅
- 游戏: 匹配游戏帧率,减少judder
2. Vsync预测算法改进
引入机器学习模型,基于历史数据更准确地预测Vsync:
- 考虑温度变化对Display刷新率的影响
- 自适应调整预测窗口大小
- 更快地检测和适应刷新率变化
3. VRR配置支持
新增VrrConfig配置,允许HAL层精确控制刷新率:
structVrrConfig{// 通知SurfaceFlinger下一帧的期望present时间intnotifyExpectedPresentTime;