源碼基于 sdk-30/11.0/R。
前言
- Android 平臺提供兩種信號,一種是硬件信號,另一種是軟件信號,由 SurfaceFlinger 進程的一個線程定時發(fā)出,硬件信號由硬件發(fā)出;
- App 進程若要通過 gpu 實現(xiàn)圖像繪制,需要在接收到 Vsync 信號的條件下進行。因此,App 進程訪問 SurfaceFlinger 進程獲取這個信號,再進行 gpu 繪制;
- Android4.1 之后增加了 Choreographer 機制,用于同 Vsync 機制配合,統(tǒng)一動畫、輸入和繪制時機;
- Choreographer 就是負(fù)責(zé)獲取 Vsync 同步信號并控制 App 線程(主線程)完成圖像繪制的類;
Choreographer 類介紹
實例初始化
/**
Coordinates the timing of animations, input and drawing.
The choreographer receives timing pulses (such as vertical synchronization) from the display subsystem then schedules work to occur as part of rendering the next display frame.
*/
public final class Choreographer {
private static final ThreadLocal<Choreographer> sThreadInstance =
new ThreadLocal<Choreographer>() {
@Override
protected Choreographer initialValue() {
Looper looper = Looper.myLooper();
if (looper == null) {
throw new IllegalStateException("The current thread must have a looper!");
}
Choreographer choreographer = new Choreographer(looper, VSYNC_SOURCE_APP);
if (looper == Looper.getMainLooper()) {
mMainInstance = choreographer;
}
return choreographer;
}
};
public static Choreographer getInstance() {
return sThreadInstance.get();
}
}
- 每個線程中保存一個 Choreographer 實例對象;
- 線程初始化 Choreographer 對象時需要提供 Looper 對象,并把 Looper 綁定到 Choreographer;
- App 中所有的 Activity 共享同一個 Choregrapher 對象,他控制者整個App中大部分視圖的繪制節(jié)奏;
構(gòu)造方法
public final class Choreographer {
public static final int CALLBACK_COMMIT = 4;
private static final int CALLBACK_LAST = CALLBACK_COMMIT;
private Choreographer(Looper looper, int vsyncSource) {
mLooper = looper;
mHandler = new FrameHandler(looper);
mDisplayEventReceiver = USE_VSYNC ? new FrameDisplayEventReceiver(looper, vsyncSource) : null;
mLastFrameTimeNanos = Long.MIN_VALUE;
// 計算一幀的時間,Android手機屏幕是60Hz的刷新頻率,就是16ms
mFrameIntervalNanos = (long)(1000000000 / getRefreshRate());
//使用數(shù)組保存五個鏈表,每個鏈表存相同類型的任務(wù):輸入、動畫、遍歷繪制等任務(wù)(CALLBACK_INPUT、CALLBACK_ANIMATION、CALLBACK_TRAVERSAL)
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));
}
}
- 根據(jù)當(dāng)前線程的 looper 創(chuàng)建 Handler 對象;
- 變量 USE_VSYNC 用于表示系統(tǒng)是否是用了 Vsync 同步機制,該值是通過讀取系統(tǒng)屬性debug.choreographer.vsync來獲取的。4.1 以上默認(rèn)是 true;
- 創(chuàng)建一個 FrameDisplayEventReceiver 對象用于請求并接收 Vsync 事件;
- 也就是數(shù)組中有五個鏈表,每個鏈表存相同類型的任務(wù):輸入、動畫、遍歷繪制等任務(wù)(CALLBACK_INPUT、CALLBACK_ANIMATION、CALLBACK_TRAVERSAL)
- 創(chuàng)建了一個大小為 5 的 CallbackQueue 隊列數(shù)組,用于保存不同類型的 Callback;
Callback 類型
// Choreographer.java
//輸入事件,首先執(zhí)行
public static final int CALLBACK_INPUT = 0;
//動畫,第二執(zhí)行
public static final int CALLBACK_ANIMATION = 1;
//插入更新的動畫,第三執(zhí)行
public static final int CALLBACK_INSETS_ANIMATION = 2;
//繪制 View,第四執(zhí)行
public static final int CALLBACK_TRAVERSAL = 3;
//提交,最后執(zhí)行。遍歷完成的提交操作,用來修正動畫啟動時間
public static final int CALLBACK_COMMIT = 4;
- 五種類型任務(wù)對應(yīng)存入對應(yīng)的 CallbackQueue 中;
- 每當(dāng)收到 VSYNC 信號時,Choreographer 將首先處理 INPUT 類型的任務(wù),然后是 ANIMATION 類型,最后才是 TRAVERSAL 類型;
FrameHandler 處理的消息
private final class FrameHandler extends Handler {
public FrameHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_DO_FRAME:
doFrame(System.nanoTime(), 0);
break;
case MSG_DO_SCHEDULE_VSYNC:
doScheduleVsync();
break;
case MSG_DO_SCHEDULE_CALLBACK:
doScheduleCallback(msg.arg1);
break;
}
}
}
FrameHandler 處理了如下三種消息:
- MSG_DO_FRAME 處理注冊在 Choreographer 的 Runnable;
- MSG_DO_SCHEDULE_VSYNC 直接請求下一幀的 VSync 信號;
- MSG_DO_SCHEDULE_CALLBACK 處理延時消息;
Choreographer 處理任務(wù)流程

choreographer-callbacks
public abstract class DisplayEventReceiver {
public void scheduleVsync() {
nativeScheduleVsync(mReceiverPtr);
}
// Called from native code.
private void dispatchVsync(long timestampNanos, long physicalDisplayId, int frame) {
onVsync(timestampNanos, physicalDisplayId, frame);
}
// Called when a vertical sync pulse is received.
public void onVsync(long timestampNanos, long physicalDisplayId, int frame) {
}
}
private final class FrameDisplayEventReceiver extends DisplayEventReceiver implements Runnable {
@Override
public void onVsync(long timestampNanos, long physicalDisplayId, int frame) {
// timestampNanos其實是本次vsync產(chǎn)生的時間,從服務(wù)端發(fā)過來
// 該消息的callback為當(dāng)前對象
Message msg = Message.obtain(mHandler, this);
// 前面添加了同步屏障,同步消息不會被執(zhí)行
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
}
@Override
public void run() {
doFrame(mTimestampNanos, mFrame);
}
void doFrame(long frameTimeNanos, int frame) {
if (!mFrameScheduled) {
return; // no work to do
}
if (frameTimeNanos < mLastFrameTimeNanos) {
// 這種情況一般是生成vsync的機制出現(xiàn)了問題,那就再申請一次
scheduleVsyncLocked();
return;
}
// intendedFrameTimeNanos是本來要繪制的時間戳,frameTimeNanos是真正的,可以在渲染工具中標(biāo)識延遲VSYNC多少
mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos);
// 移除mFrameScheduled判斷,說明處理開始了
mFrameScheduled = false;
doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);
doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
doCallbacks(Choreographer.CALLBACK_INSETS_ANIMATION, frameTimeNanos);
doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos);
}
void doCallbacks(int callbackType, long frameTimeNanos) {
// 獲取當(dāng)前類型 Callback 鏈表的首部節(jié)點
CallbackRecord callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(
now / TimeUtils.NANOS_PER_MS);
try {
// 遍歷鏈表,執(zhí)行任務(wù)。比如執(zhí)行 ViewRootImpl#TraversalRunnable 任務(wù)。
for (CallbackRecord c = callbacks; c != null; c = c.next) {
c.run(frameTimeNanos);
}
} finally {
// 遍歷鏈表,重置 Callback
}
}
}
scheduleVsync() 方法通過 native 方法 nativeScheduleVsync() 向 SurfaceFlinger 服務(wù)注冊,即在下一次脈沖接收后會調(diào)用 DisplayEventReceiver 的 dispatchVsync() 方法;
底層向應(yīng)用層發(fā)送VSYNC信號,java 層通過 dispatchVsync() 接收,最后回調(diào)在FrameDisplayEventReceiver#onVsync();
處理繪制任務(wù)
// ViewRootImpl.java
public ViewRootImpl(Context context, Display display, IWindowSession session,
boolean useSfChoreographer) {
//獲取Choreographer實例。useSfChoreographer 默認(rèn) false。
mChoreographer = useSfChoreographer
? Choreographer.getSfInstance() : Choreographer.getInstance();
}
final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
final class TraversalRunnable implements Runnable {
@Override
public void run() {
doTraversal();
}
}
void doTraversal() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
// 移除同步屏障
mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
// 開始測量,布局和繪制流程
performTraversals();
}
}
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
// 同步屏障的作用是可以攔截 Looper 對同步消息的獲取和分發(fā)。
// 加入同步屏障之后,Looper 只會獲取和處理異步消息,如果沒有異步消息那么就會進入阻塞狀態(tài);
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
}
}
void unscheduleTraversals() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
mChoreographer.removeCallbacks(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
}
}
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
checkThread();
mLayoutRequested = true;
scheduleTraversals();
}
}
VSync 機制
Android 系統(tǒng)每隔 16ms 發(fā)出 VSYNC 信號,觸發(fā)對UI進行渲染,VSync是Vertical Synchronization(垂直同步)的縮寫。

VSync

VSync
- 16ms 內(nèi)只會申請一次垂直同步信號;
- VSync信號由SurfaceFlinger實現(xiàn)并定時發(fā)送。
總結(jié)
- Choreographer 的職責(zé)是統(tǒng)一處理輸入、繪制、動畫和提交任務(wù);
- 主線程通過 Choreographer 把不同類型的 Callback 添加到單鏈表中。時間到后,根據(jù) Callback 優(yōu)先級遍歷各個單鏈表執(zhí)行任務(wù);
參考
[1] 屏幕刷新機制Choreographer原理分析
[2] Android屏幕刷新機制解析
[3] Android 屏幕刷新機制與Choreographer全面解讀