Choreographer的作用
結(jié)合上篇Android 繪制原理可知道,屏幕每16ms 顯示frame buffer上的幀信息,然后frame buffer和back buffer進(jìn)行互換,并發(fā)送vsync信號(hào),此時(shí)CPU會(huì)中斷其它操作,來(lái)通過(guò)ChoreGrapher去確定顯示的幀信息(控件應(yīng)該怎么畫(huà),畫(huà)在哪個(gè)位置,畫(huà)多大),當(dāng)這些信息確定后,GPU再根據(jù)這些信息刷新back buffer的信息,刷新完成后 back buffer 和 frame buffer互換位置。
Choreographer的具體運(yùn)行過(guò)程
Choreographer主要做如下工作,下面我們逐一分析
- 注冊(cè)監(jiān)聽(tīng),當(dāng)收到vsync信號(hào),會(huì)回調(diào)
- 接受并保存控制幀的信息的任務(wù)
- 調(diào)用4個(gè)回調(diào)鏈表確定幀信息
源碼分析
注冊(cè)監(jiān)聽(tīng)-FrameDisplayEventReceiver
FrameDisplayEventReceiver是ChoreoGrapher的私有類,當(dāng)收到vsync信號(hào),且c/c++回調(diào)開(kāi)關(guān)是打開(kāi)的會(huì)調(diào)用FrameDisplayEventReceiver的onVsync()。
FrameDisplayEventReceiver在Choreographer被創(chuàng)建,具體在第4行:
//frameworks/base/core/java/android/view/Choreographer.java
private Choreographer(Looper looper) {
mLooper = looper;
mHandler = new FrameHandler(looper);
mDisplayEventReceiver = USE_VSYNC ? new FrameDisplayEventReceiver(looper) : null;
mLastFrameTimeNanos = Long.MIN_VALUE;
mFrameIntervalNanos = (long) (1000000000 / getRefreshRate());
mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1];
for (int i = 0; i <= CALLBACK_LAST; i++) {
mCallbackQueues[i] = new CallbackQueue();
}
}
FrameDisplayEventReceiver繼承自DisplayEventReceiver,我們跟進(jìn)去看構(gòu)造方法,會(huì)發(fā)現(xiàn)調(diào)用了nativeInit(),這是個(gè)native方法:
frameworks/base/core/java/android/view/DisplayEventReceiver.java
/**
* Creates a display event receiver.
*
* @param looper The looper to use when invoking callbacks.
*/
public DisplayEventReceiver(Looper looper) {
if (looper == null) {
throw new IllegalArgumentException("looper must not be null");
}
mMessageQueue = looper.getQueue();
mReceiverPtr = nativeInit(new WeakReference<DisplayEventReceiver>(this), mMessageQueue);
mCloseGuard.open("dispose");
}
通過(guò)FrameDisplayEventReceiver就是通過(guò)這個(gè)nativeInit()方法注冊(cè)進(jìn)去的。
在nativeInit()中將我們java層傳過(guò)來(lái)的DisplayEventReceiver和mMessageQueue 作為參數(shù)new了個(gè)NativeDisplayEventReceiver對(duì)象,然后調(diào)用NativeDisplayEventReceiver->initialize().
//frameworks/base/core/jni/android_view_DisplayEventReceiver.cpp
static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,
jobject messageQueueObj) {
sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
if (messageQueue == NULL) {
jniThrowRuntimeException(env, "MessageQueue is not initialized.");
return 0;
}
sp<NativeDisplayEventReceiver> receiver = new NativeDisplayEventReceiver(env,
receiverWeak, messageQueue);
status_t status = receiver->initialize();
if (status) {
String8 message;
message.appendFormat("Failed to initialize display event receiver. status=%d", status);
jniThrowRuntimeException(env, message.string());
return 0;
}
我們找到NativeDisplayEventReceiver構(gòu)造方法
frameworks/base/core/jni/android_view_DisplayEventReceiver.cpp
NativeDisplayEventReceiver::NativeDisplayEventReceiver(JNIEnv* env,
jobject receiverWeak, const sp<MessageQueue>& messageQueue) :
DisplayEventDispatcher(messageQueue->getLooper()),
mReceiverWeakGlobal(env->NewGlobalRef(receiverWeak)),
mMessageQueue(messageQueue), mWaitingForVsync(false) {
ALOGV("receiver %p ~ Initializing display event receiver.", this);
}
通過(guò)下面代碼知道NativeDisplayEventReceiver是繼承自DisplayEventDispatcher的,而NativeDisplayEventReceiver中沒(méi)有initialize(),于是我們知道status_t status = receiver->initialize();調(diào)用的是NativeDisplayEventReceiver的initialize():
//frameworks\base\libs\androidfw\DisplayEventDispatcher.cpp
status_t DisplayEventDispatcher::initialize() {
status_t result = mReceiver.initCheck();
if (result) {
ALOGW("Failed to initialize display event receiver, status=%d", result);
return result;
}
int rc = mLooper->addFd(mReceiver.getFd(), 0, Looper::EVENT_INPUT,
this, NULL);
if (rc < 0) {
return UNKNOWN_ERROR;
}
return OK;
}
DisplayEventDispatcher是繼承自LooperCallback 的,在DisplayEventDispatcher::initialize()中調(diào)用了
int rc = mLooper->addFd(mReceiver.getFd(), 0, Looper::EVENT_INPUT,
this, NULL);
這句話的意思是監(jiān)聽(tīng)mReceiver,一旦有數(shù)據(jù)到來(lái)則回調(diào)this(此處DisplayEventDispatcher)中所復(fù)寫(xiě)LooperCallback對(duì)象的 handleEvent。
//frameworks/base/libs/androidfw/DisplayEventDispatcher.cpp
int DisplayEventDispatcher::handleEvent(int, int events,
... ...
// Drain all pending events, keep the last vsync.
nsecs_t vsyncTimestamp;
int32_t vsyncDisplayId;
uint32_t vsyncCount;
//清除所有的pending事件,只保留最后一次vsync
if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount)) {
ALOGV("dispatcher %p ~ Vsync pulse: timestamp=%" PRId64 ", id=%d, count=%d",
this, ns2ms(vsyncTimestamp), vsyncDisplayId, vsyncCount);
mWaitingForVsync = false;
//分發(fā)Vsync
dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount);
}
return 1; // keep the callback
}
handleEvent()倒數(shù)第5行會(huì)調(diào)用到NativeDisplayEventReceiver的復(fù)寫(xiě)的dispatchVsync():
frameworks/base/core/jni/android_view_DisplayEventReceiver.cpp
void NativeDisplayEventReceiver::dispatchVsync(nsecs_t timestamp, int32_t id, uint32_t count) {
JNIEnv* env = AndroidRuntime::getJNIEnv();
ScopedLocalRef<jobject> receiverObj(env, jniGetReferent(env, mReceiverWeakGlobal));
if (receiverObj.get()) {
ALOGV("receiver %p ~ Invoking vsync handler.", this);
//此處調(diào)用到Java層的DisplayEventReceiver對(duì)象的dispatchVsync()方法
env->CallVoidMethod(receiverObj.get(),
gDisplayEventReceiverClassInfo.dispatchVsync, timestamp, id, count);
ALOGV("receiver %p ~ Returned from vsync handler.", this);
}
mMessageQueue->raiseAndClearException(env, "dispatchVsync");
}
調(diào)用4個(gè)回調(diào)鏈表確定幀信息
在NativeDisplayEventReceiver::dispatchVsync通過(guò)如下代碼調(diào)用java層DisplayEventReceiver的dispatchVsync().
env->CallVoidMethod(receiverObj.get(),
gDisplayEventReceiverClassInfo.dispatchVsync, timestamp, id, count);
我們回到NativeDisplayEventReceiver.dispatchVsync():
//android.view.DisplayEventReceiver
// Called from native code.
@SuppressWarnings("unused")
private void dispatchVsync(long timestampNanos, int builtInDisplayId, int frame) {
onVsync(timestampNanos, builtInDisplayId, frame);
}
Choreographer對(duì)象實(shí)例化的過(guò)程,創(chuàng)建的對(duì)象是DisplayEventReceiver子類 FrameDisplayEventReceiver對(duì)象,我們進(jìn)入FrameDisplayEventReceiver復(fù)寫(xiě)的onVsync方法:
private final class FrameDisplayEventReceiver extends DisplayEventReceiver
implements Runnable {
private boolean mHavePendingVsync;
private long mTimestampNanos;
private int mFrame;
@Override
public void onVsync(long timestampNanos, int builtInDisplayId, int frame) {
//忽略來(lái)自第二顯示屏的Vsync
if (builtInDisplayId != SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN) {
scheduleVsync();
return;
}
...
mTimestampNanos = timestampNanos;
mFrame = frame;
//該消息的callback為當(dāng)前對(duì)象FrameDisplayEventReceiver
Message msg = Message.obtain(mHandler, this);
msg.setAsynchronous(true);
//此處mHandler為FrameHandler
mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
}
@Override
public void run() {
mHavePendingVsync = false;
doFrame(mTimestampNanos, mFrame); //【見(jiàn)小節(jié)2.8】
}
}
可見(jiàn)onVsync()中是通過(guò)FrameHandler向主線程Looper發(fā)送了一個(gè)自帶callback的消息, callback為FrameDisplayEventReceiver。 當(dāng)主線程Looper執(zhí)行到該消息時(shí),則調(diào)用FrameDisplayEventReceiver.run(),緊接著便是調(diào)用doFrame()
//android.view.Choreographer
void doFrame(long frameTimeNanos, int frame) {
final long startNanos;
synchronized (mLock) {
if (!mFrameScheduled) {
return; // no work to do
}
if (DEBUG_JANK && mDebugPrintNextFrameTimeDelta) {
mDebugPrintNextFrameTimeDelta = false;
Log.d(TAG, "Frame time delta: "
+ ((frameTimeNanos - mLastFrameTimeNanos) * 0.000001f) + " ms");
}
long intendedFrameTimeNanos = frameTimeNanos;
startNanos = System.nanoTime();
final long jitterNanos = startNanos - frameTimeNanos;
if (jitterNanos >= mFrameIntervalNanos) {
final long skippedFrames = jitterNanos / mFrameIntervalNanos;
if (skippedFrames >= SKIPPED_FRAME_WARNING_LIMIT) {
Log.i(TAG, "Skipped " + skippedFrames + " frames! "
+ "The application may be doing too much work on its main thread.");
}
final long lastFrameOffset = jitterNanos % mFrameIntervalNanos;
if (DEBUG_JANK) {
Log.d(TAG, "Missed vsync by " + (jitterNanos * 0.000001f) + " ms "
+ "which is more than the frame interval of "
+ (mFrameIntervalNanos * 0.000001f) + " ms! "
+ "Skipping " + skippedFrames + " frames and setting frame "
+ "time to " + (lastFrameOffset * 0.000001f) + " ms in the past.");
}
frameTimeNanos = startNanos - lastFrameOffset;
}
if (frameTimeNanos < mLastFrameTimeNanos) {
if (DEBUG_JANK) {
Log.d(TAG, "Frame time appears to be going backwards. May be due to a "
+ "previously skipped frame. Waiting for next vsync.");
}
scheduleVsyncLocked();
return;
}
mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos);
mFrameScheduled = false;
mLastFrameTimeNanos = frameTimeNanos;
}
try {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Choreographer#doFrame");
AnimationUtils.lockAnimationClock(frameTimeNanos / TimeUtils.NANOS_PER_MS);
mFrameInfo.markInputHandlingStart();
doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);
mFrameInfo.markAnimationsStart();
doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
mFrameInfo.markPerformTraversalsStart();
doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos);
} finally {
AnimationUtils.unlockAnimationClock();
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
if (DEBUG_FRAMES) {
final long endNanos = System.nanoTime();
Log.d(TAG, "Frame " + frame + ": Finished, took "
+ (endNanos - startNanos) * 0.000001f + " ms, latency "
+ (startNanos - frameTimeNanos) * 0.000001f + " ms.");
}
}
每調(diào)用一次scheduleFrameLocked(),則mFrameScheduled為true,能執(zhí)行一次 doFrame()操作。doframe的大致流程如下:

總結(jié)起來(lái)其實(shí)主要是三個(gè)操作:
1.設(shè)置當(dāng)前frame的啟動(dòng)時(shí)間。
判斷是否跳幀,若跳幀修正當(dāng)前frame的啟動(dòng)時(shí)間到最近的VSync信號(hào)時(shí)間。如果沒(méi)跳幀,當(dāng)前frame啟動(dòng)時(shí)間直接設(shè)置為當(dāng)前VSync信號(hào)時(shí)間。修正完時(shí)間后,無(wú)論當(dāng)前frame是否跳幀,使得當(dāng)前frame的啟動(dòng)時(shí)間與VSync信號(hào)還是在一個(gè)節(jié)奏上的,可能可能延后了一到幾個(gè)周期,但是節(jié)奏點(diǎn)還是吻合的。
如下圖所示是時(shí)間修正的一個(gè)例子,

由于第二個(gè)frame執(zhí)行超時(shí),第三個(gè)frame實(shí)際啟動(dòng)時(shí)間比第三個(gè)VSync信號(hào)到來(lái)時(shí)間要晚,因?yàn)檫@時(shí)候延時(shí)比較小,沒(méi)有超過(guò)一個(gè)時(shí)鐘周期,系統(tǒng)還是將frameTimeNanos3傳給回調(diào),回調(diào)拿到的時(shí)間和VSync信號(hào)同步。
再來(lái)看看下圖:

由于第二個(gè)frame執(zhí)行時(shí)間超過(guò)2個(gè)時(shí)鐘周期,導(dǎo)致第三個(gè)frame延后執(zhí)行時(shí)間大于一個(gè)時(shí)鐘周期,系統(tǒng)認(rèn)為這時(shí)候影響較大,判定為跳幀了,將第三個(gè)frame的時(shí)間修正為frameTimeNanos4,比VSync真正到來(lái)的時(shí)間晚了一個(gè)時(shí)鐘周期。
時(shí)間修正,既保證了doFrame操作和VSync保持同步節(jié)奏,又保證實(shí)際啟動(dòng)時(shí)間與記錄的時(shí)間點(diǎn)相差不會(huì)太大,便于同步及分析。
2.判斷是否事件回溯
在doframe中 如下代碼判斷是否時(shí)間回溯:
if (frameTimeNanos < mLastFrameTimeNanos) {
if (DEBUG_JANK) {
Log.d(TAG, "Frame time appears to be going backwards. May be due to a "
+ "previously skipped frame. Waiting for next vsync.");
}
scheduleVsyncLocked();
return;
}
mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos);
mFrameScheduled = false;
mLastFrameTimeNanos = frameTimeNanos;
我們?cè)诳聪翭rameDisplayEventReceiver :
private final class FrameDisplayEventReceiver extends DisplayEventReceiver
implements Runnable {
···· ···
@Override
public void onVsync(long timestampNanos, int builtInDisplayId, int frame) {
··· ···
mTimestampNanos = timestampNanos;
mFrame = frame;
Message msg = Message.obtain(mHandler, this);
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
}
@Override
public void run() {
mHavePendingVsync = false;
doFrame(mTimestampNanos, mFrame);
}
}
可知是通過(guò)handler發(fā)送message, 然后走run方法執(zhí)行doFrame的。
同樣看下圖

由于第二個(gè)frame執(zhí)行時(shí)間超過(guò)3個(gè)時(shí)鐘周期,導(dǎo)致第三個(gè)frame延后執(zhí)行時(shí)間大于兩個(gè)個(gè)時(shí)鐘周期,系統(tǒng)認(rèn)為這時(shí)候影響較大,判定為跳幀了,將第三個(gè)frame的時(shí)間修正為frameTimeNanos5,比VSync真正到來(lái)的時(shí)間晚了一個(gè)時(shí)鐘周期。當(dāng)圖中第5個(gè)vsync到來(lái)時(shí),消息隊(duì)列中還有3個(gè)任務(wù)(取出frameTimeNanos1和frameTimeNanos2所對(duì)應(yīng)的任務(wù),還剩frameTimeNanos3和frameTimeNanos4和frameTimeNanos5),當(dāng)執(zhí)行frameTimeNanos4所對(duì)應(yīng)的任務(wù)時(shí),此時(shí)通過(guò)frameTimeNanos為frameTimeNanos4 ,mLastFrameTimeNanos 為frameTimeNanos5的值,此時(shí)frameTimeNanos<mLastFrameTimeNanos ,即時(shí)間回溯。
3.順序執(zhí)行callBack隊(duì)列里面的callback.
然后接下來(lái)看看doCallbacks的執(zhí)行過(guò)程:
//android.view.Choreographer
void doCallbacks(int callbackType, long frameTimeNanos) {
CallbackRecord callbacks;
synchronized (mLock) {
// We use "now" to determine when callbacks become due because it's possible
// for earlier processing phases in a frame to post callbacks that should run
// in a following phase, such as an input event that causes an animation to start.
final long now = System.nanoTime();
callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(
now / TimeUtils.NANOS_PER_MS);
if (callbacks == null) {
return;
}
mCallbacksRunning = true;
// Update the frame time if necessary when committing the frame.
// We only update the frame time if we are more than 2 frames late reaching
// the commit phase. This ensures that the frame time which is observed by the
// callbacks will always increase from one frame to the next and never repeat.
// We never want the next frame's starting frame time to end up being less than
// or equal to the previous frame's commit frame time. Keep in mind that the
// next frame has most likely already been scheduled by now so we play it
// safe by ensuring the commit time is always at least one frame behind.
if (callbackType == Choreographer.CALLBACK_COMMIT) {
final long jitterNanos = now - frameTimeNanos;
Trace.traceCounter(Trace.TRACE_TAG_VIEW, "jitterNanos", (int) jitterNanos);
if (jitterNanos >= 2 * mFrameIntervalNanos) {
final long lastFrameOffset = jitterNanos % mFrameIntervalNanos
+ mFrameIntervalNanos;
if (DEBUG_JANK) {
Log.d(TAG, "Commit callback delayed by " + (jitterNanos * 0.000001f)
+ " ms which is more than twice the frame interval of "
+ (mFrameIntervalNanos * 0.000001f) + " ms! "
+ "Setting frame time to " + (lastFrameOffset * 0.000001f)
+ " ms in the past.");
mDebugPrintNextFrameTimeDelta = true;
}
frameTimeNanos = now - lastFrameOffset;
mLastFrameTimeNanos = frameTimeNanos;
}
}
}
try {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, CALLBACK_TRACE_TITLES[callbackType]);
for (CallbackRecord c = callbacks; c != null; c = c.next) {
if (DEBUG_FRAMES) {
Log.d(TAG, "RunCallback: type=" + callbackType
+ ", action=" + c.action + ", token=" + c.token
+ ", latencyMillis=" + (SystemClock.uptimeMillis() - c.dueTime));
}
c.run(frameTimeNanos);
}
} finally {
synchronized (mLock) {
mCallbacksRunning = false;
do {
final CallbackRecord next = callbacks.next;
recycleCallbackLocked(callbacks);
callbacks = next;
} while (callbacks != null);
}
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}
callback的類型有以下4種,除了文章一開(kāi)始提到的3中外,還有一個(gè)CALLBACK_COMMIT。
CALLBACK_INPUT:輸入
CALLBACK_ANIMATION:動(dòng)畫(huà)
CALLBACK_TRAVERSAL:遍歷,執(zhí)行measure、layout、draw
CALLBACK_COMMIT:遍歷完成的提交操作,用來(lái)修正動(dòng)畫(huà)啟動(dòng)時(shí)間
然后看上面的源碼,分析一下每個(gè)callback的執(zhí)行過(guò)程:
1.callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked( now / TimeUtils.NANOS_PER_MS);得到執(zhí)行時(shí)間在當(dāng)前時(shí)間之前的所有CallBack,保存在單鏈表中。每種類型的callback按執(zhí)行時(shí)間先后順序排序分別存在一個(gè)單鏈表里面。為了保證當(dāng)前callback執(zhí)行時(shí)新post進(jìn)來(lái)的callback在下一個(gè)frame時(shí)才被執(zhí)行,這個(gè)地方extractDueCallbacksLocked會(huì)將需要執(zhí)行的callback和以后執(zhí)行的callback斷開(kāi)變成兩個(gè)鏈表,新post進(jìn)來(lái)的callback會(huì)被放到后面一個(gè)鏈表中。當(dāng)前frame只會(huì)執(zhí)行前一個(gè)鏈表中的callback,保證了在執(zhí)行callback時(shí),如果callback中Post相同類型的callback,這些新加的callback將在下一個(gè)frame啟動(dòng)后才會(huì)被執(zhí)行。
2.接下來(lái),看一大段注釋,如果類型是CALLBACK_COMMIT,并且當(dāng)前frame渲染時(shí)間超過(guò)了兩個(gè)時(shí)鐘周期,則將當(dāng)前提交時(shí)間修正為上一個(gè)垂直同步信號(hào)時(shí)間。為了保證下一個(gè)frame的提交時(shí)間和當(dāng)前frame時(shí)間相差為一且不重復(fù)。
這個(gè)地方注釋挺難看懂,實(shí)際上這個(gè)地方CALLBACK_COMMIT是為了解決ValueAnimator的一個(gè)問(wèn)題而引入的,主要是解決因?yàn)楸闅v時(shí)間過(guò)長(zhǎng)導(dǎo)致動(dòng)畫(huà)時(shí)間啟動(dòng)過(guò)長(zhǎng),時(shí)間縮短,導(dǎo)致跳幀,這里修正動(dòng)畫(huà)第一個(gè)frame開(kāi)始時(shí)間延后來(lái)改善,這時(shí)候才表示動(dòng)畫(huà)真正啟動(dòng)。為什么不直接設(shè)置當(dāng)前時(shí)間而是回溯一個(gè)時(shí)鐘周期之前的時(shí)間呢?看注釋,這里如果設(shè)置為當(dāng)前frame時(shí)間,因?yàn)閯?dòng)畫(huà)的第一個(gè)frame其實(shí)已經(jīng)繪制完成,第二個(gè)frame這時(shí)候已經(jīng)開(kāi)始了,設(shè)置為當(dāng)前時(shí)間會(huì)導(dǎo)致這兩個(gè)frame時(shí)間一樣,導(dǎo)致沖突。詳細(xì)情況請(qǐng)看官方針對(duì)這個(gè)問(wèn)題的修改。Fix animation start jank due to expensive layout operations.
如下圖所示:

3.接下來(lái)就是調(diào)用c.run(frameTimeNanos);執(zhí)行回調(diào)。
例如,你可以寫(xiě)一個(gè)自定義的FPSFrameCallback繼承自Choreographer.FrameCallback,實(shí)現(xiàn)里面的doFrame方法。
public class FPSFrameCallback implements Choreographer.FrameCallback{
@Override
public void doFrame(long frameTimeNanos){
//do something
}
}
通過(guò)
Choreographer.getInstance().postFrameCallback(new FPSFrameCallback());
把你的回調(diào)添加到Choreographer之中,那么在下一個(gè)frame被渲染的時(shí)候就會(huì)回調(diào)你的callback,執(zhí)行你定義的doFrame操作,這時(shí)候你就可以獲取到這一幀的開(kāi)始渲染時(shí)間并做一些自己想做的事情了。
自此FrameDisplayEventReceiver注冊(cè)及其回調(diào)完成
接受并保存控制幀的信息的任務(wù)
Choreographer維護(hù)了一個(gè)隊(duì)列數(shù)組,這個(gè)數(shù)組有4個(gè)元素分別對(duì)應(yīng)于
- INPUT:輸入事件
- ANIMATION:動(dòng)畫(huà)
- TRAVERSAL:窗口刷新
- COMMIT:主要是為了處理動(dòng)畫(huà)的bug
這四個(gè)添加的流程大致上是一致的,我們以TRAVERSAL進(jìn)行說(shuō)明,從ViewRootImp的scheduleTraversals()方法說(shuō)起:
//android.view.ViewRootImpl
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
if (!mUnbufferedInputDispatch) {
scheduleConsumeBatchedInput();
}
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
會(huì)發(fā)現(xiàn)調(diào)用了mChoreographer.postCallback():
//android.view.Choreographer
public void postCallback(int callbackType, Runnable action, Object token) {
postCallbackDelayed(callbackType, action, token, 0);
}
繼續(xù)看postCallbackDelayed()
//android.view.Choreographer
public void postCallbackDelayed(int callbackType,
Runnable action, Object token, long delayMillis) {
if (action == null) {
throw new IllegalArgumentException("action must not be null");
}
if (callbackType < 0 || callbackType > CALLBACK_LAST) {
throw new IllegalArgumentException("callbackType is invalid");
}
postCallbackDelayedInternal(callbackType, action, token, delayMillis);
}
繼續(xù)看postCallbackDelayedInternal()
//android.view.Choreographer
private void postCallbackDelayedInternal(int callbackType,
Object action, Object token, long delayMillis) {
if (DEBUG_FRAMES) {
Log.d(TAG, "PostCallback: type=" + callbackType
+ ", action=" + action + ", token=" + token
+ ", delayMillis=" + delayMillis);
}
synchronized (mLock) {
final long now = SystemClock.uptimeMillis();
final long dueTime = now + delayMillis;
//添加到mCallbackQueues隊(duì)列
mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
if (dueTime <= now) {
scheduleFrameLocked(now);
} else {
Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
msg.arg1 = callbackType;
msg.setAsynchronous(true);
//發(fā)送消息MSG_DO_SCHEDULE_CALLBACK
mHandler.sendMessageAtTime(msg, dueTime);
}
}
}
在這里將callback添加到隊(duì)列,如果 不是延時(shí)直接調(diào)用cheduleFrameLocked()方法,如果是則通過(guò)handler調(diào)用,F(xiàn)rameHandler 代碼如下:
private final class FrameHandler extends Handler {
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); //【見(jiàn)小節(jié)3.5】
break;
}
}
}
doScheduleCallback():
void doScheduleCallback(int callbackType) {
synchronized (mLock) {
if (!mFrameScheduled) {
final long now = SystemClock.uptimeMillis();
if (mCallbackQueues[callbackType].hasDueCallbacksLocked(now)) {
scheduleFrameLocked(now); //【見(jiàn)小節(jié)3.6】
}
}
}
}
發(fā)現(xiàn)調(diào)用的是scheduleFrameLocked():
private void scheduleFrameLocked(long now) {
if (!mFrameScheduled) {
mFrameScheduled = true;
if (USE_VSYNC) {
if (DEBUG_FRAMES) {
Log.d(TAG, "Scheduling next frame on vsync.");
}
// If running on the Looper thread, then schedule the vsync immediately,
// otherwise post a message to schedule the vsync from the UI thread
// as soon as possible.
if (isRunningOnLooperThreadLocked()) {
scheduleVsyncLocked();
} else {
Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
msg.setAsynchronous(true);
mHandler.sendMessageAtFrontOfQueue(msg);
}
} else {
final long nextFrameTime = Math.max(
mLastFrameTimeNanos / TimeUtils.NANOS_PER_MS + sFrameDelay, now);
if (DEBUG_FRAMES) {
Log.d(TAG, "Scheduling next frame in " + (nextFrameTime - now) + " ms.");
}
Message msg = mHandler.obtainMessage(MSG_DO_FRAME);
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, nextFrameTime);
}
}
}
該方法的功能:
- 當(dāng)運(yùn)行在Looper線程,則立刻調(diào)度scheduleVsyncLocked();
- 當(dāng)運(yùn)行在其他線程,則通過(guò)發(fā)送一個(gè)消息到Looper線程,然后再執(zhí)行scheduleVsyncLocked();
private void scheduleVsyncLocked() {
mDisplayEventReceiver.scheduleVsync(); //【見(jiàn)小節(jié)3.8】
}
mDisplayEventReceiver對(duì)象是在Choreographer的實(shí)例化過(guò)程所創(chuàng)建的。
public void scheduleVsync() {
if (mReceiverPtr == 0) {
...
} else {
nativeScheduleVsync(mReceiverPtr);
}
}
至此分析大致流程是

找到nativeScheduleVsync所對(duì)應(yīng)的c++文件
//frameworks/base/core/jni/android_view_DisplayEventReceiver.cpp
static void nativeScheduleVsync(JNIEnv* env, jclass clazz, jlong receiverPtr) {
sp<NativeDisplayEventReceiver> receiver =
reinterpret_cast<NativeDisplayEventReceiver*>(receiverPtr);
status_t status = receiver->scheduleVsync();
··· ···
}
}
因?yàn)镹ativeDisplayEventReceiver 繼承DisplayEventReceiver,找到DisplayEventReceiver中scheduleVsync():
//android.view.DisplayEventReceiver
status_t DisplayEventDispatcher::scheduleVsync() {
··· ····
status_t status = mReceiver.requestNextVsync();
··· ···
}
該方法的作用請(qǐng)求下一次Vsync信息處理。 當(dāng)Vsync信號(hào)到來(lái),由于mFrameScheduled=true,則繼續(xù)CallbackRecord.run()方法。
參考:
Android的16ms和垂直同步以及三重緩存
Choreographer原理
Android Choreographer 源碼分析