Choreographer(编排者)是 Android 系统中核心的帧时序协调组件,负责统一调度输入事件、动画、UI 绘制 的执行时机,确保所有操作对齐屏幕的 VSync(垂直同步)信号,避免掉帧、画面撕裂等问题。Android 12 在 Choreographer 与 SurfaceFlinger(SF)的交互效率、刷新率适配等方面做了优化,以下从核心流程展开详解。
一、核心背景概念
在深入流程前,先明确关键依赖:
- VSync 信号:由 HWComposer(HWC,硬件合成器)生成,频率等于屏幕刷新率(如 60/90/120Hz),是帧渲染的 "时间基准"。
- SurfaceFlinger(SF) :系统级服务,负责管理屏幕帧缓冲区、合成多应用图层,其内部的
EventThread专门负责向应用分发 VSync 信号。 - DisplayEventReceiver:Choreographer 与 SF 通信的底层抽象,通过 JNI+Binder 实现跨进程 VSync 信号接收。
二、App 侧 Choreographer 的创建(含与 SF EventThread 建立通道)
Choreographer 是线程单例 (绑定 Looper),UI 线程的 Choreographer 在首次调用Choreographer.getInstance()时创建, ViewRootImpl 创建的时候就会调用Choreographer.getInstance(),核心流程包含 "自身初始化" 和 "与 SF 建立 VSync 通信通道" 两步。
2.1 Choreographer 的初始化流程
1. 单例创建逻辑
每个拥有 Looper 的线程(如 UI 线程)有且仅有一个 Choreographer,源码核心逻辑:
//ViewRootImpl.java
public ViewRootImpl(@UiContext Context context, Display display, IWindowSession session,
boolean useSfChoreographer) {
mChoreographer = Choreographer.getInstance();
}
// Choreographer.java
private static final ThreadLocal<Choreographer> sThreadLocal = new ThreadLocal<>();
public static Choreographer getInstance() {
return getInstance(Looper.myLooper()); // 绑定当前线程的Looper
}
public static Choreographer getInstance(Looper looper) {
if (looper == null) throw new NullPointerException("looper must not be null");
Choreographer choreographer = sThreadLocal.get();
if (choreographer == null) {
// 首次创建时初始化
choreographer = new Choreographer(looper);
sThreadLocal.set(choreographer);
}
return choreographer;
}
2. Choreographer 构造函数(核心组件初始化)
private Choreographer(Looper looper, int vsyncSource) {
mLooper = looper;
// 1. 帧处理Handler(绑定Looper,处理VSync触发的帧消息)
mHandler = new FrameHandler(looper);
// 2. 核心:与SF通信的DisplayEventReceiver(封装VSync接收逻辑)
mDisplayEventReceiver = new FrameDisplayEventReceiver(looper, vsyncSource);
mLastFrameTimeNanos = Long.MIN_VALUE;
mFrameIntervalNanos = (long)(1000000000 / getRefreshRate());
//3. 回调队列,不同的地方都注册了vsync监听
mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1];
for (int i = 0; i <= CALLBACK_LAST; i++) {
mCallbackQueues[i] = new CallbackQueue();
}
// b/68769804: For low FPS experiments.
setFPSDivisor(SystemProperties.getInt(ThreadedRenderer.DEBUG_FPS_DIVISOR, 1));
}
2.2 与 SF EventThread 建立通信通道(关键)
Choreographer 通过FrameDisplayEventReceiver(继承自DisplayEventReceiver)完成与 SF 的连接,核心是DisplayEventReceiver的 native 层初始化。
1. FrameDisplayEventReceiver 的创建
FrameDisplayEventReceiver是 Choreographer 的内部类,专门处理 VSync 信号的接收和转发:
private final class FrameDisplayEventReceiver extends DisplayEventReceiver {
public FrameDisplayEventReceiver(Looper looper, int vsyncSource) {
super(looper, vsyncSource, 0);
}
// 接收SF发来的VSync信号后的回调
@Override
public void onVsync(long timestampNanos, long physicalDisplayId, int frame) {
// 转换时间戳为毫秒,发送MSG_DO_FRAME消息到FrameHandler
long now = System.nanoTime();
if (timestampNanos > now) {
timestampNanos = now;
}
Message msg = mHandler.obtainMessage(MSG_DO_FRAME, frame, 0, timestampNanos);
msg.setAsynchronous(true); // Android 12优化:异步消息减少阻塞
mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
mPosted = false;
}
}
2. native 层初始化(与 SF 建立连接)
DisplayEventReceiver的构造函数会调用nativeInit,完成跨进程通信通道的建立:
// DisplayEventReceiver.java
public DisplayEventReceiver(Looper looper, int vsyncSource, int eventRegistration) {
mMessageQueue = looper.getQueue();
mReceiverPtr = nativeInit(new WeakReference<DisplayEventReceiver>(this),
mMessageQueue,
vsyncSource, eventRegistration);
}
// 底层nativeInit逻辑(Android 12源码,简化)
// frameworks/base/core/jni/android_view_DisplayEventReceiver.cpp
jlong nativeInit(JNIEnv* env, jobject thiz, jobject weakThiz, jobject messageQueueObj, jint displayId) {
// 1. 获取MessageQueue的native层对象(Looper的底层实现)
sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
// 2. 创建DisplayEventDispatcher(核心分发器)
sp<DisplayEventDispatcher> dispatcher = new DisplayEventDispatcher(env, weakThiz, messageQueue, displayId);
// 3. 初始化Dispatcher:通过SurfaceComposerClient连接SF
return reinterpret_cast<jlong>(dispatcher.get());
}
//DisplayEventReceiver.cpp
// 最终调用到
DisplayEventReceiver::DisplayEventReceiver(
ISurfaceComposer::VsyncSource vsyncSource,
ISurfaceComposer::EventRegistrationFlags eventRegistration) {
sp<ISurfaceComposer> sf(ComposerService::getComposerService());
if (sf != nullptr) {
//与SF 建立IDisplayEventConnection 通道
mEventConnection = sf->createDisplayEventConnection(vsyncSource, eventRegistration);
if (mEventConnection != nullptr) {
mDataChannel = std::make_unique<gui::BitTube>();
//建立BitTube(本地套接字)
// SF 是通过本地套接字传递vsync事件给到DisplayEventReceiver的
mEventConnection->stealReceiveChannel(mDataChannel.get());
}
}
}
3. SF 侧的处理(EventThread)
- SF 的
EventThread是每个 Display 的专属线程,负责管理所有 App 的 VSync 注册请求。 - 当 App 的
DisplayEventDispatcher调用initialize()时,会通过SurfaceComposerClient向 SF 发送注册请求,EventThread会创建一个Connection对象(关联 App 的 Binder 接口),并将其加入 VSync 分发列表。 - 至此,App 侧 Choreographer 与 SF 的 EventThread 完成双向通信通道的建立
三、Choreographer 从 SF 获取 VSync 信号的完整流程
VSync 信号的流转是 "SF 生成 → 分发 → App 接收 → 帧处理" 的闭环,Android 12 对该流程做了多维度优化(如异步消息、刷新率自适应),核心步骤如下:
3.1 触发 VSync 请求(App 侧主动发起)
App 侧需要渲染新帧时(如View.postInvalidate()、ValueAnimator动画)是, 用通过Choreographer.postCallback() 或postFrameCallback()申请下个vsync。 调用 mDisplayEventReceiver.scheduleVsync(),最终native的DisplayEventReceiver 同binder 调用的SF requestNextVsync()
// ViewRootImpl.java
void invalidate() {
mDirty.set(0, 0, mWidth, mHeight);
if (!mWillDrawSoon) {
scheduleTraversals();
}
}
void scheduleTraversals() {
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
}
// Choreographer.java
public void postCallback(int callbackType, Runnable action, Object token) {
postCallbackDelayed(callbackType, action, token, 0);
}
postCallbackDelayed()
postCallbackDelayedInternal();
scheduleVsyncLocked();
mDisplayEventReceiver.scheduleVsync();
// DisplayEventReceiver.cpp
status_t DisplayEventReceiver::requestNextVsync() {
if (mEventConnection != nullptr) {
mEventConnection->requestNextVsync();
return NO_ERROR;
}
return NO_INIT;
}
// 最终会通过DisplayEventReceiver的binder
.... binder .....
// SF 端
//EventThread.cpp
void EventThreadConnection::requestNextVsync() {
mEventThread->requestNextVsync(this);
}
void EventThread::requestNextVsync(const sp<EventThreadConnection>& connection) {
if (connection->vsyncRequest == VSyncRequest::None) {
connection->vsyncRequest = VSyncRequest::Single;
mCondition.notify_all(); //唤醒EventThread的线程,监听下一个vsync
}
}
void EventThread::threadMain(std::unique_lock<std::mutex>& lock) {
if (mState != nextState) {
if (mState == State::VSync) {
mVSyncSource->setVSyncEnabled(false);
} else if (nextState == State::VSync) {
mVSyncSource->setVSyncEnabled(true); //监听下一个vsync
}
mState = nextState;
}
}
3.2 SF 生成并分发 VSync 信号
1. VSync 信号的生成
SF 的VSyncThread监听 HWC 的 VSync 中断:HWC 根据屏幕刷新率(如 60Hz)生成硬件级 VSync 信号,触发VSyncThread的回调。(Vsync 不一定是HWC上传的,可能是FS VSyncPredictor根据)
2. EventThread 分发 VSync
VSyncThread将 VSync 事件推送给对应 Display 的EventThread。EventThread遍历其管理的所有Connection(即已注册 VSync 的 App),通过 Binder 跨进程将 VSync 事件(包含时间戳、帧号、物理屏 ID)发送给 App 侧的DisplayEventDispatcher。
3.3 App 侧接收 VSync 信号
DisplayEventDispatcher通过 epoll 监听 SF 的 Binder 消息,接收到 VSync 事件后,调用onVsync回调(Java 层FrameDisplayEventReceiver.onVsync)。FrameDisplayEventReceiver将 VSync 时间戳封装为MSG_DO_FRAME消息,发送给FrameHandler(Android 12 新增:消息标记为异步,避免被同步消息阻塞)。
3.4 Choreographer 处理帧逻辑(doFrame)
FrameHandler处理MSG_DO_FRAME时,调用Choreographer.doFrame(),按优先级执行回调:
void doFrame(long frameTimeNanos, int frame) {
long startNanos = System.nanoTime();
try {
// 1. 处理输入回调(最高优先级:触摸/按键等)
doCallbacks(CALLBACK_INPUT, frameTimeNanos);
// 2. 处理动画回调(第二优先级:ValueAnimator/属性动画)
doCallbacks(CALLBACK_ANIMATION, frameTimeNanos);
// 3. 处理Traversal回调(最低优先级:measure/layout/draw)
doCallbacks(CALLBACK_TRAVERSAL, frameTimeNanos);
// 4. 处理提交回调(Android 12新增:帧提交到SF后的回调)
doCallbacks(CALLBACK_COMMIT, frameTimeNanos);
} finally {
// 标记帧处理完成
mFrameScheduled = false;
}
// Android 12优化:帧耗时统计,超过阈值则标记掉帧
long frameDurationNanos = System.nanoTime() - startNanos;
if (frameDurationNanos > mFrameIntervalNanos) {
long overrunNanos = frameDurationNanos - mFrameIntervalNanos;
Log.w(TAG, "Frame time is " + overrunNanos / 1000000 + "ms overrun!");
}
}
3.5 关键补充:Android 12 的 VSync 优化
- 异步 MSG_DO_FRAME:避免 VSync 消息被同步消息(如 Handler.post)阻塞,减少帧延迟。
- 动态刷新率(DRR)适配 :Choreographer 的
RefreshRateTracker实时监测帧需求,自动请求 SF 切换刷新率(如静态 UI 时降为 60Hz,动画时升为 120Hz)。 - 减少 JNI 调用开销 :
DisplayEventDispatcher的 native 层逻辑优化,合并多次 Binder 调用,降低跨层耗时。 - 多屏 VSync 支持 :
DisplayEventReceiver支持指定displayId,适配折叠屏 / 多屏场景的 VSync 分发。
四、核心总结
4.1 关键流程闭环
App触发帧需求 → Choreographer.postCallback → FrameDisplayEventReceiver.scheduleVsync()
→ SF EventThread注册VSync请求 → HWC生成VSync → SF EventThread分发VSync
→ App侧DisplayEventReceiver接收VSync → FrameHandler发送MSG_DO_FRAME
→ Choreographer.doFrame()执行输入/动画/绘制回调 → 帧渲染完成提交到SF
4.2 核心设计要点
- 线程单例:Choreographer 绑定 Looper,确保每个线程的帧时序独立,避免多线程干扰。
- 优先级调度:输入 > 动画 > 绘制,保障交互响应优先于 UI 渲染。
- VSync 对齐:所有帧操作严格对齐 VSync,避免掉帧和画面撕裂。
- 跨进程通信:通过 DisplayEventReceiver+Binder 实现 App 与 SF 的 VSync 信号传递。
4.3 常见问题解析
- 掉帧原因 :
doFrame执行时间超过一帧时长(如 60Hz 下 16.6ms),导致下一个 VSync 到来时未完成当前帧。 - VSync 丢失:SF 的 EventThread 分发延迟,或 App 侧 Looper 阻塞(如主线程耗时操作)。
- Android 12 流畅度提升:异步消息、刷新率自适应、JNI 优化共同减少帧延迟和掉帧概率。
五、源码参考路径(Android 12)
- Choreographer:
frameworks/base/core/java/android/view/Choreographer.java - DisplayEventReceiver:
frameworks/base/core/java/android/view/DisplayEventReceiver.java - native 层 DisplayEventDispatcher:
frameworks/base/core/jni/android_view_DisplayEventReceiver.cpp - SF EventThread:
frameworks/native/services/surfaceflinger/EventThread.cpp - VSyncThread:
frameworks/native/services/surfaceflinger/VSyncThread.cpp
