「这是我参与11月更文挑战的第14天,活动详情查看:2021最后一次更文挑战」
上篇我们介绍到Choreographer去请求Vsync信号,本篇我们接着讲解当收到SurfaceFlinger发来的Vsync信号后是如何去处理的。
当下一个Vsync信号发出的时候SurfaceFlinger会通知我们,会Choreographer中的回调FrameDisplayEventReceiver的onVsync方法。
private final class FrameDisplayEventReceiver extends DisplayEventReceiver
implements Runnable {
//...
@Override
// 接受到Vsync信号的回调
public void onVsync(long timestampNanos, long physicalDisplayId, int frame) {
long now = System.nanoTime();
mTimestampNanos = timestampNanos;
mFrame = frame;
Message msg = Message.obtain(mHandler, this); //public void run()
msg.setAsynchronous(true);
//timestampNanos消息触发时间,时间戳去处理时间
mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
}
//执行doFrame
@Override
public void run() {
mHavePendingVsync = false;
doFrame(mTimestampNanos, mFrame);
}
}
timestampNanos是Vsync信号的时间戳,在onVsync方法中发了一个异步消息到工作线程中。时间戳去处理时间。到时间后会执行run方法,所以紧接着去分析doFrame方法。
//frameTimeNanos时间戳
void doFrame(long frameTimeNanos, int frame) {
final long startNanos;
synchronized (mLock) {
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;
frameTimeNanos = startNanos - lastFrameOffset;
}
}
//第二阶段
}
doFrame主要分为两个阶段,现在分析第一阶段,frameTimeNanos标识这一帧的时间戳,jitterNanos计算当前时间和时间戳的时间间隔,间隔越大表示这一帧的处理已经延时了,如果延时超过一个周期,则计算超过了几个周期skippedFrames。并打印相应的日志。这部分主要就是掉帧计算。
接着看第二部分,处理callback。
void doFrame(long frameTimeNanos, int frame) {
//...
doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);
doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos);
}
callback有四种类型,每种类型都对应一个CallbackQueues,就是一个单链表。给Vsync分别分发到这四种callback。执行对应的doCallback函数。
void doCallbacks(int callbackType, long frameTimeNanos) {
CallbackRecord callbacks;
synchronized (mLock) {
final long now = System.nanoTime();
//取出那些到时间的callback
callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(
now / TimeUtils.NANOS_PER_MS);
//...
//执行callback
for (CallbackRecord c = callbacks; c != null; c = c.next) {
c.run(frameTimeNanos);
}
//...
}
}
主要工作就是取出那些到时间的callback,去执行run方法,在前面传的callback是.CALLBACK_TRAVERSAL,就是去准备回执
void scheduleTraversals() {
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
}
}
mTraversalRunnable主要工作是去进行真正的绘制操作。
下面总结一下这个流程: