Choreographer源码阅读
之前已经在很多地方看到过Choreographer的身影,必须要仔细的看一遍Choreographer源码以理解其实现原理。Choreographer请求和接受来自底层的VSYNC信号,给上层应用提供一个稳定的周期,去处理Input事件、动画、更新布局等。
1、Choreographer构造及初始化
Choreographer直译为编舞者,看完源码更能理解Choreographer为何能称之为"编舞者"。本篇基于android12-platform-release源码,将来再看可能有变化。
1.1、Choreographer构造
先从Choreographer的构造方法开始看:初始化FrameHandler、FrameDisplayEventReceiver以及CallbackQueue等重要对象。
private Choreographer(Looper looper, int vsyncSource) {
//调用线程的Looper,所在线程必须有Looper
mLooper = looper;
//使用所在线程的Looper构造一个Handler,处理消息
mHandler = new FrameHandler(looper);
//USE_VSYNC默认为true,构造FrameDisplayEventReceiver。注册底层VSYNC回调
mDisplayEventReceiver = USE_VSYNC
? new FrameDisplayEventReceiver(looper, vsyncSource)
: null;
mLastFrameTimeNanos = Long.MIN_VALUE;
mFrameIntervalNanos = (long)(1000000000 / getRefreshRate());
//初始化几种类型的CallbackQueue队列
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));
}Choreographer的构造方法是private,框架必然提供了获取Choreographer实例的方法(常用设计方法)。继续往下看:
1.2、Choreographer初始化/获取
Choreographer的getInstance()方法可以获取当前线程的唯一Choreographer实例,调用该方法所在的线程必须有Looper。
/**
* Gets the choreographer for the calling thread. Must be called from
* a thread that already has a {@link android.os.Looper} associated with it.
*
* @return The choreographer for this thread.
* @throws IllegalStateException if the thread does not have a looper.
*/
public static Choreographer getInstance() {
return sThreadInstance.get();
}当前线程的唯一Choreographer实例借助ThreadLocal初始化并获取,ThreadLocal原理在Thread和ThreadLocal一文有详细说明。
// Thread local storage for the 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;
}
};如果获取Choreographer的线程为主线程,还会初始化并持有主线程的Choreographer实例mMainInstance:
private static volatile Choreographer mMainInstance;通过getMainThreadInstance()方法可以获得主线程的Choreographer实例,不过该方法以及被标记为@hide不可使用,说明将在以后的API中删除。
/**
* @return The Choreographer of the main thread, if it exists, or {@code null} otherwise.
* @hide
*/
public static Choreographer getMainThreadInstance() {
return mMainInstance;
}同样的还有一个获取Choreographer实例的方法getSfInstance()需要了解一下,和前面刚提到的getInstance()方法仅两词只差:
@UnsupportedAppUsage
public static Choreographer getSfInstance() {
return sSfThreadInstance.get();
}同样,使用sSfThreadInstance存储实例。唯一区别在于VSYNC来源标志不同,使用DisplayEventReceiver中的VSYNC_SOURCE_SURFACE_FLINGER,即只要Surface Flinger正在处理帧,就发送VSYNC信号,而不是固定周期发送VSYNC信号。
// Thread local storage for the SF choreographer.
private static final ThreadLocal<Choreographer> sSfThreadInstance =
new ThreadLocal<Choreographer>() {
@Override
protected Choreographer initialValue() {
Looper looper = Looper.myLooper();
if (looper == null) {
throw new IllegalStateException("The current thread must have a looper!");
}
return new Choreographer(looper, VSYNC_SOURCE_SURFACE_FLINGER);
}
};应用开发者不可调用该方法,仅在ViewRootImpl初始化的构造方法中用到了此方法。ViewRootImpl在DecorView添加到Window中的流程一文中有提到过。
public ViewRootImpl(@UiContext Context context, Display display, IWindowSession session,
boolean useSfChoreographer) {
mContext = context;
...
//初始化ViewRootImpl中的Choreographer,默认为false,使用后者: getInstance()
mChoreographer = useSfChoreographer
? Choreographer.getSfInstance() : Choreographer.getInstance();
}再仔细看源码,会发现所有用到ViewRootImpl构造方法所传入的useSfChoreographer参数值均为false,getSfInstance()方法并没有被使用到,可能此方法也会在Android迭代的过程中被删除。
public ViewRootImpl(Context context, Display display) {
this(context, display, WindowManagerGlobal.getWindowSession(),
false /* useSfChoreographer */);
}
public ViewRootImpl(@UiContext Context context, Display display, IWindowSession session) {
this(context, display, session, false /* useSfChoreographer */);
}2、Choreographer源码解析
继续往下看,Choreographer中的两个内部类:FrameHandler和FrameDisplayEventReceiver。这两个类的实例在1.1节Choreographer构造方法中初始化。
2.1、FrameHandler处理消息
FrameHandler继承自Handler,负责完成三个重要的操作:执行回调doFrame、请求VSYNC、调度Callback。所有向此FrameHandler发送的Message都用setAsynchronous(true)设置成了异步消息。
private final class FrameHandler extends Handler {
//使用Choreographer所在线程的Looper处理消息
public FrameHandler(Looper looper) {
//这里创建的是同步Hhandler,但是后面所有消息都是异步消息
super(looper);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_DO_FRAME:
doFrame(System.nanoTime(), 0, new DisplayEventReceiver.VsyncEventData());
break;
case MSG_DO_SCHEDULE_VSYNC:
doScheduleVsync();
break;
case MSG_DO_SCHEDULE_CALLBACK:
doScheduleCallback(msg.arg1);
break;
}
}
}2.2、FrameDisplayEventReceiver接收VSYNC信号
DisplayEventReceiver继承自DisplayEventReceiver,用来接收和请求VSYNC信号。DisplayEventReceiver收到信号后,底层调用dispatchVsync()方法:
// Called from native code.
@SuppressWarnings("unused")
private void dispatchVsync(long timestampNanos, long physicalDisplayId, int frame,
long frameTimelineVsyncId, long frameDeadline, long frameInterval) {
onVsync(timestampNanos, physicalDisplayId, frame,
new VsyncEventData(frameTimelineVsyncId, frameDeadline, frameInterval));
}进而调用onVsync()方法,该方法在DisplayEventReceiver中是空方法。
/**
* Called when a vertical sync pulse is received.
* The recipient should render a frame and then call {@link #scheduleVsync}
* to schedule the next vertical sync pulse.
*
* @param timestampNanos The timestamp of the pulse, in the {@link System#nanoTime()}
* timebase.
* @param physicalDisplayId Stable display ID that uniquely describes a (display, port) pair.
* @param frame The frame number. Increases by one for each vertical sync interval.
* @param vsyncEventData The vsync event data.
*/
public void onVsync(long timestampNanos, long physicalDisplayId, int frame,
VsyncEventData vsyncEventData) {
}Choreographer中的FrameDisplayEventReceiver内部类则实现了这个onVsync()空方法:
private final class FrameDisplayEventReceiver extends DisplayEventReceiver
implements Runnable {
private boolean mHavePendingVsync;
private long mTimestampNanos;
private int mFrame;
private VsyncEventData mLastVsyncEventData = new VsyncEventData();
public FrameDisplayEventReceiver(Looper looper, int vsyncSource) {
super(looper, vsyncSource, 0);
}
@Override
public void onVsync(long timestampNanos, long physicalDisplayId, int frame,
VsyncEventData vsyncEventData) {
try {
//当前时间
long now = System.nanoTime();
//VSYNC时间比当前时间还超前
if (timestampNanos > now) {
Log.w(TAG, "Frame time is " + ((timestampNanos - now) * 0.000001f)
+ " ms in the future! Check that graphics HAL is generating vsync "
+ "timestamps using the correct timebase.");
//回退到当前时间
timestampNanos = now;
}
if (mHavePendingVsync) {
Log.w(TAG, "Already have a pending vsync event. There should only be "
+ "one at a time.");
} else {
mHavePendingVsync = true;
}
//保持VSYNC时间等相关信息
mTimestampNanos = timestampNanos;
mFrame = frame;
mLastVsyncEventData = vsyncEventData;
//通过obtain()方法获取可重用Message,自身作为Message的callback
Message msg = Message.obtain(mHandler, this);
//消息设置为异步消息,Choreographer中的所有Messag都是异步消息
msg.setAsynchronous(true);
//向FrameHandler发送消息
mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}
//前面发送的消息到Handler,最后执行的是callback中的这个run()方法
@Override
public void run() {
mHavePendingVsync = false;
doFrame(mTimestampNanos, mFrame, mLastVsyncEventData);
}
}FrameDisplayEventReceiver同时也实现了Runnable接口,在onVsync()方法中将自身作为Message中携带的callback,根据Handler中Callback的作用一文,可以知道消息最后执行的是FrameDisplayEventReceiver实现的run()方法:
@Override
public void run() {
mHavePendingVsync = false;
//执行Choreographer核心方法:doFrame()
doFrame(mTimestampNanos, mFrame, mLastVsyncEventData);
}3、Choreographer核心方法:doFrame()
在run()方法中调用Choreographer的 doFrame() 方法。框架的方法都有点长,耐心的逐行去看,很容易理解。流程图先欠着,直接上代码:
void doFrame(long frameTimeNanos, int frame,
DisplayEventReceiver.VsyncEventData vsyncEventData) {
//真正执行doFrame绘制该帧的时间。
final long startNanos;
//使用Native帧率。以前用的是mFrameIntervalNanos变量:Android手机屏幕是60Hz的刷新频率,就是16ms
final long frameIntervalNanos = vsyncEventData.frameInterval;
try {
if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
Trace.traceBegin(Trace.TRACE_TAG_VIEW,
"Choreographer#doFrame " + vsyncEventData.id);
}
synchronized (mLock) {
//mFrameScheduled在scheduleFrameLocked(long now)方法中被置位true,也就是有postCallback任务才会执行
if (!mFrameScheduled) {
traceMessage("Frame not scheduled");
return; // no work to do
}
//打印这一帧开始和上一帧执行的时间间隔,俗称跳帧时间。
if (DEBUG_JANK && mDebugPrintNextFrameTimeDelta) {
mDebugPrintNextFrameTimeDelta = false;
Log.d(TAG, "Frame time delta: "
+ ((frameTimeNanos - mLastFrameTimeNanos) * 0.000001f) + " ms");
}
//保持当前帧的VSYNC时间,frameTimeNanos是vsync消息要求绘制该帧的时间。
//不会超过当前时间,在onVsync方法中会将超前的时间回退到当前时间。
long intendedFrameTimeNanos = frameTimeNanos;
//真正执行doFrame绘制该帧的时间
startNanos = System.nanoTime();
//当前帧的开始时间和来自VSYNC要求绘制该帧的时间差
final long jitterNanos = startNanos - frameTimeNanos;
//时间差大于一个时钟周期,认为发生跳帧。
//以前API这里判断的变量是mFrameIntervalNanos,Android手机屏幕是60Hz的刷新频率,就是16ms。
if (jitterNanos >= frameIntervalNanos) {
//跳过的帧数
final long skippedFrames = jitterNanos / frameIntervalNanos;
//掉帧超过30帧打印Log提示
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 % frameIntervalNanos;
if (DEBUG_JANK) {
Log.d(TAG, "Missed vsync by " + (jitterNanos * 0.000001f) + " ms "
+ "which is more than the frame interval of "
+ (frameIntervalNanos * 0.000001f) + " ms! "
+ "Skipping " + skippedFrames + " frames and setting frame "
+ "time to " + (lastFrameOffset * 0.000001f) + " ms in the past.");
}
//根据帧偏差,修正VSYNC要求绘制帧的时间。
frameTimeNanos = startNanos - lastFrameOffset;
}
//如果修正后的时间回溯,小于上一帧处理的时间。调用scheduleVsyncLocked()请求下一个时钟信号。
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.");
}
traceMessage("Frame time goes backward");
//调用scheduleVsyncLocked()请求下一个时钟信号。
scheduleVsyncLocked();
return;
}
//低帧率设备适配,新特性。
if (mFPSDivisor > 1) {
long timeSinceVsync = frameTimeNanos - mLastFrameTimeNanos;
if (timeSinceVsync < (frameIntervalNanos * mFPSDivisor) && timeSinceVsync > 0) {
traceMessage("Frame skipped due to FPSDivisor");
scheduleVsyncLocked();
return;
}
}
//保持计算后的各种信息
mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos, vsyncEventData.id,
vsyncEventData.frameDeadline, startNanos, vsyncEventData.frameInterval);
mFrameScheduled = false;
mLastFrameTimeNanos = frameTimeNanos;
mLastFrameIntervalNanos = frameIntervalNanos;
mLastVsyncEventData = vsyncEventData;
}
//执行各种Callback回调
AnimationUtils.lockAnimationClock(frameTimeNanos / TimeUtils.NANOS_PER_MS);
mFrameInfo.markInputHandlingStart();
doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos, frameIntervalNanos);
mFrameInfo.markAnimationsStart();
doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos, frameIntervalNanos);
doCallbacks(Choreographer.CALLBACK_INSETS_ANIMATION, frameTimeNanos,
frameIntervalNanos);
mFrameInfo.markPerformTraversalsStart();
doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos, frameIntervalNanos);
doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos, frameIntervalNanos);
} finally {
AnimationUtils.unlockAnimationClock();
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
//打印帧log,在调试过程中,看系统log有帮助
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.");
}
}4、Choreographer回调方法doCallbacks
doFrame()方法的最后调用一系列doCallbacks()方法按顺序执行各种类型的Callback:
void doFrame(long frameTimeNanos, int frame,DisplayEventReceiver.VsyncEventData vsyncEventData) {
...
AnimationUtils.lockAnimationClock(frameTimeNanos / TimeUtils.NANOS_PER_MS);
//在动画之前,先处理Input输入事件
mFrameInfo.markInputHandlingStart();
doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos, frameIntervalNanos);
//遍历之前处理动画,新增了一种CALLBACK_INSETS_ANIMATION
mFrameInfo.markAnimationsStart();
doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos, frameIntervalNanos);
doCallbacks(Choreographer.CALLBACK_INSETS_ANIMATION, frameTimeNanos,frameIntervalNanos);
//执行遍历操作:measure、layout、draw
mFrameInfo.markPerformTraversalsStart();
doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos, frameIntervalNanos);
//提交操作,用来修正动画启动时间
doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos, frameIntervalNanos);
...
}4.1、几种回调队列
Choreographer定义了几种类的CALLBACK:
@UnsupportedAppUsage
private final CallbackQueue[] mCallbackQueues;
public static final int CALLBACK_INPUT = 0;
public static final int CALLBACK_ANIMATION = 1;
public static final int CALLBACK_INSETS_ANIMATION = 2;
public static final int CALLBACK_TRAVERSAL = 3;
public static final int CALLBACK_COMMIT = 4;
private static final int CALLBACK_LAST = CALLBACK_COMMIT;CallbackQueue队列在Choreographer构造方法中初始化:
private Choreographer(Looper looper, int vsyncSource) {
...
//队列数组大小为5: 0 1 2 3 4
mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1];
//分别初始化这5个不同类型的回调队列
for (int i = 0; i <= CALLBACK_LAST; i++) {
mCallbackQueues[i] = new CallbackQueue();
}
...
}4.2、doCallbacks()回调
看一下执行的doCallbacks()回调方法,这个方法在Animator属性动画源码中也有详细的解析。
void doCallbacks(int callbackType, long frameTimeNanos, long frameIntervalNanos) {
CallbackRecord callbacks;
synchronized (mLock) {
final long now = System.nanoTime();
//根据Callbacktype从mCallbackQueues取出对应的CallbackQueue,再从中拿出CallbackRecord
callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(
now / TimeUtils.NANOS_PER_MS);
//没有需要执行的CallbackRecord直接返回
if (callbacks == null) {
return;
}
//标记为:正在执行Callback
mCallbacksRunning = true;
//callbackType类型为CALLBACK_COMMIT特殊处理
if (callbackType == Choreographer.CALLBACK_COMMIT) {
final long jitterNanos = now - frameTimeNanos;
if (jitterNanos >= 2 * frameIntervalNanos) {
final long lastFrameOffset = jitterNanos % frameIntervalNanos
+ frameIntervalNanos;
//打印卡顿信息
if (DEBUG_JANK) {
Log.d(TAG, "Commit callback delayed by " + (jitterNanos * 0.000001f)
+ " ms which is more than twice the frame interval of "
+ (frameIntervalNanos * 0.000001f) + " ms! "
+ "Setting frame time to " + (lastFrameOffset * 0.000001f)
+ " ms in the past.");
mDebugPrintNextFrameTimeDelta = true;
}
frameTimeNanos = now - lastFrameOffset;
mLastFrameTimeNanos = frameTimeNanos;
}
}
}
try {
//挨个执行CallbackRecord
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);
}
}
}4.3、举例
前面已经对Choreographer机制有了比较系统的认识。再举几个例子,开发中哪些地方都直接或者间接的使用到了Choreographer。
①CALLBACK_INPUT:在ViewRootImpl的scheduleConsumeBatchedInput()方法中:
void scheduleConsumeBatchedInput() {
if (!mConsumeBatchedInputScheduled && !mConsumeBatchedInputImmediatelyScheduled) {
mConsumeBatchedInputScheduled = true;
//postCallback类型CALLBACK_INPUT
mChoreographer.postCallback(Choreographer.CALLBACK_INPUT,
mConsumedBatchedInputRunnable, null);
}
}②CALLBACK_ANIMATION:在View的postOnAnimation(Runnable action)方法中:
public void postOnAnimation(Runnable action) {
final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
//postCallback类型CALLBACK_ANIMATION
attachInfo.mViewRootImpl.mChoreographer.postCallback(
Choreographer.CALLBACK_ANIMATION, action, null);
} else {
getRunQueue().post(action);
}
}③CALLBACK_INSETS_ANIMATION:在ViewRootInsetsControllerHost中的postInsetsAnimationCallback(Runnable r)方法中:
@Override
public void postInsetsAnimationCallback(Runnable r) {
mViewRoot.mChoreographer.postCallback(Choreographer.CALLBACK_INSETS_ANIMATION, r,
null /* token */);
} ④CALLBACK_TRAVERSAL:在ViewRootImpl中的scheduleTraversals()方法中:
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
//postCallback类型CALLBACK_TRAVERSAL
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}⑤CALLBACK_COMMIT:在AnimationHandler的postCommitCallback(runnable)方法中:
@Override
public void postCommitCallback(Runnable runnable) {
//postCallback类型CALLBACK_COMMIT
mChoreographer.postCallback(Choreographer.CALLBACK_COMMIT, runnable, null);
}看完Choreographer的源码,了解其实现原理:接收底层VSYNC信号,为上层应用提供稳定刷新机制;接受应用各种回调任务,然后根据底层VSYNC信号统一处理。如此承上启下运作,实现输入事件分发、动画刷新、布局绘制等一系列开发者所熟悉的场景。
分析绘制性能可以用Systrace抓取trace(或AndroidStudio自带的Profiler抓取的运行trace):
阅读Choreographer源码,对分析日常的卡顿、定位绘制过程中所遇到的问题很有帮助。
相关源码:
googlesource/platform/frameworks/base/core/java/android/hardware/display/
googlesource/platform/frameworks/base/services/core/java/com/android/server/display
https://source.android.google.cn/devices/graphics
https://developer.android.google.cn/reference/android/view/Choreographer?hl=en
https://developer.android.google.cn/reference/android/view/Choreographer.FrameCallback?hl=en
https://developer.android.google.cn/ndk/reference/group/choreographer?hl=en


