/** * 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"); }
通过下面代码知道NativeDisplayEventReceiver是继承自DisplayEventDispatcher的,而NativeDisplayEventReceiver中没有initialize(),于是我们知道status_t status = receiver->initialize();调用的是NativeDisplayEventReceiver的initialize():
// Called from native code. @SuppressWarnings("unused") private void dispatchVsync(long timestampNanos, int builtInDisplayId, int frame) { onVsync(timestampNanos, builtInDisplayId, frame); }
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) { //忽略来自第二显示屏的Vsync if (builtInDisplayId != SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN) { scheduleVsync(); return; } ... mTimestampNanos = timestampNanos; mFrame = frame; //该消息的callback为当前对象FrameDisplayEventReceiver Message msg = Message.obtain(mHandler, this); msg.setAsynchronous(true); //此处mHandler为FrameHandler mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_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; }
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; }
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); } }
1.callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked( now / TimeUtils.NANOS_PER_MS);得到执行时间在当前时间之前的所有CallBack,保存在单链表中。每种类型的callback按执行时间先后顺序排序分别存在一个单链表里面。为了保证当前callback执行时新post进来的callback在下一个frame时才被执行,这个地方extractDueCallbacksLocked会将需要执行的callback和以后执行的callback断开变成两个链表,新post进来的callback会被放到后面一个链表中。当前frame只会执行前一个链表中的callback,保证了在执行callback时,如果callback中Post相同类型的callback,这些新加的callback将在下一个frame启动后才会被执行。
2.接下来,看一大段注释,如果类型是CALLBACK_COMMIT,并且当前frame渲染时间超过了两个时钟周期,则将当前提交时间修正为上一个垂直同步信号时间。为了保证下一个frame的提交时间和当前frame时间相差为一且不重复。 这个地方注释挺难看懂,实际上这个地方CALLBACK_COMMIT是为了解决ValueAnimator的一个问题而引入的,主要是解决因为遍历时间过长导致动画时间启动过长,时间缩短,导致跳帧,这里修正动画第一个frame开始时间延后来改善,这时候才表示动画真正启动。为什么不直接设置当前时间而是回溯一个时钟周期之前的时间呢?看注释,这里如果设置为当前frame时间,因为动画的第一个frame其实已经绘制完成,第二个frame这时候已经开始了,设置为当前时间会导致这两个frame时间一样,导致冲突。详细情况请看官方针对这个问题的修改。Fix animation start jank due to expensive layout operations.
//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"); }
synchronized (mLock) { final long now = SystemClock.uptimeMillis(); final long dueTime = now + delayMillis; //添加到mCallbackQueues队列 mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
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); //【见小节3.5】 break; } } }
doScheduleCallback():
1 2 3 4 5 6 7 8 9 10
void doScheduleCallback(int callbackType) { synchronized (mLock) { if (!mFrameScheduled) { final long now = SystemClock.uptimeMillis(); if (mCallbackQueues[callbackType].hasDueCallbacksLocked(now)) { scheduleFrameLocked(now); //【见小节3.6】 } } } }
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); } } }