基于Android R版本
Choreographer
Choreographer 是一个线程中仅存在一个实例,因此在UI线程只有一个 Choreographer 存在(一个应用中的单例),Choreographer 扮演 Android 渲染链路中承上启下的角色,其作用为:负责控制视图的绘制;
在Android4.1之后增加了Choreographer机制,用于同Vsync机制配合,实现统一调度界面绘图;
- 负责接收和处理 App 的各种更新消息和回调,等到 Vsync 到来的时候统一处理。比如集中处理 Input(主要是 Input 事件的处理) 、Animation(动画相关)、Traversal(包括 measure、layout、draw 等操作) ,判断卡顿掉帧情况,记录 CallBack 耗时等;
- Choreographer负责请求(FrameDisplayEventReceiver.scheduleVsync)和接收Vsync信号(FrameDisplayEventReceiver.onVsync);
- 控制外部输入事件处理,动画执行,UI变化,以及提交执行都是在同一个类中做的处理,即是Choreographer;
- Choreographer支持5种类型事件:输入、绘制、动画、insets动画、提交,并通过postCallback在对应需要同步vsync进行刷新处进行注册,等待回调;
- 每次执行的时候,Choreographer会根据当前的时间,只处理事件链表中最后一个事件,当有耗时操作在主线程时,事件不能及时执行,就会出现所谓的“跳帧”,“卡顿”现象;
- Choreographer的共有方法postCallback(callbackType, Object)是往事件链表中放事件的方法,而doFrame()是消耗这些事件的方法;
- Choreographer监听底层Vsync信号,一旦接收到回调信号,则通过doFrame统一对java层5种类型事件进行回调;
FrameHandler
private final class FrameHandler extends Handler {
// 使用Choreographer所在线程的Looper处理消息
public FrameHandler(Looper looper) {
// 这里创建的是同步Handler,但是后面所有消息都是异步消息
// 即后续使用的就是Handler Callback的方式发送消息的,而不是通过sendMessage处理Message
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;
}
}
}
用于发送异步消息,有延迟的任务发延迟消息、不在原线程的发到原线程、没开启Vsync的直接走doFrame()方法取执行绘制;
FrameHandler主要在UI线程处理3种类型的消息:
- MSG_DO_FRAME:开始渲染下一帧的操作;
- MSG_DO_SCHEDULE_VSYNC:请求Vsync信号;
- MSG_DO_SCHEDULE_CALLBACK:请求执行callback;
CallbackQueue
public static final int CALLBACK_COMMIT = 4;
private static final int CALLBACK_LAST = CALLBACK_COMMIT;
@UnsupportedAppUsage
private final CallbackQueue[] mCallbackQueues;
mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1];
在Choreographer的构造方法中,创建了CallbackQueue数组,这个数组用于保存不同类型Callback的队列,对应的个数就是Callback Type size;
Callback 类型
//输入事件,首先执行
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;
Choreographer 初始化
我们在执行addView的时候,会创建ViewRootImpl实例,在ViewRootImpl的构造方法中,会获取Choreographer实例:
mChoreographer = useSfChoreographer
? Choreographer.getSfInstance() : Choreographer.getInstance();
useSfChoreographer在ViewRootImpl中默认为false,即默认使用getInstance获取Choreographer实例;
public static Choreographer getInstance() {
return sThreadInstance.get();
}
@UnsupportedAppUsage
public static Choreographer getSfInstance() {
return sSfThreadInstance.get();
}
// 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;
}
};
// 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);
}
};
在Choreographer的初始化过程中,需要传入对应的VSync的信号类型:
- VSYNC_SOURCE_APP:VSync由硬件发出的硬件信号,应用进程监听VSync信号并通知给Choreographer;
- VSYNC_SOURCE_SURFACE_FLINGER:由SurfaceFlinger进程的一个线程定时发出的软件信号;
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));
}
FrameDisplayEventReceiver 初始化
private final class FrameDisplayEventReceiver extends DisplayEventReceiver
implements Runnable {
private boolean mHavePendingVsync;
private long mTimestampNanos;
private int mFrame;
public FrameDisplayEventReceiver(Looper looper, int vsyncSource) {
super(looper, vsyncSource, CONFIG_CHANGED_EVENT_SUPPRESS);
}
// TODO(b/116025192): physicalDisplayId is ignored because SF only emits VSYNC events for
// the internal display and DisplayEventReceiver#scheduleVsync only allows requesting VSYNC
// for the internal display implicitly.
@Override
public void onVsync(long timestampNanos, long physicalDisplayId, int frame) {
// Post the vsync event to the Handler.
// The idea is to prevent incoming vsync events from completely starving
// the message queue. If there are no messages in the queue with timestamps
// earlier than the frame time, then the vsync event will be processed immediately.
// Otherwise, messages that predate the vsync event will be handled first.
// 当前时间
long now = System.nanoTime();
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;
// 通过obtain()方法获取可重用Message,自身作为Message的callback,即后续会调用FrameDisplayEventReceiver的run()方法
Message msg = Message.obtain(mHandler, this);
// 消息设置为异步消息,Choreographer中的所有Messag都是异步消息
msg.setAsynchronous(true);
// 向FrameHandler发送消息
mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
}
// 前面发送的消息到Handler,最后执行的是callback中的这个run()方法
@Override
public void run() {
mHavePendingVsync = false;
// 执行Choreographer核心方法:doFrame()
doFrame(mTimestampNanos, mFrame);
}
}
Choreographer 工作流程
我们以StatusBar hide场景为例,分析Choreographer的工作流程;
scheduleVsync
执行到scheduleVsync()方法之后,就需要等待VSYNC信号的上报;
doFrame
在doFrame()方法中,首先先计算帧率相关的一些信息,后续将其信息保存到mFrameInfo对象中进行维护;
最后会依次调用上述描述过的CallbackQueue(Input、Animation、Insets_Animation、Traversal、Commit);
doCallbacks
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();
// 根据Callback Type从mCallbackQueues中取出对应的CallbackQueue,再从中取出CallbackRecord
callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(
now / TimeUtils.NANOS_PER_MS);
// 没有需要执行的CallbackRecord直接返回
if (callbacks == null) {
return;
}
// 标记为:正在执行Callback
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.
// callbackType类型为CALLBACK_COMMIT特殊处理
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]);
// 按个执行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);
}
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}
我们以CallbackType = CALLBACK_ANIMATION为例:
private static final class CallbackRecord {
public CallbackRecord next;
public long dueTime;
public Object action; // Runnable or FrameCallback
public Object token;
@UnsupportedAppUsage
public void run(long frameTimeNanos) {
if (token == FRAME_CALLBACK_TOKEN) {
((FrameCallback)action).doFrame(frameTimeNanos);
} else {
((Runnable)action).run();
}
}
}
从mCallbackQueues[CALLBACK_ANIMATION]中拿到CallbackRecord对象,执行其run()方法;
我们通过追溯CallbackRecord的action的赋值逻辑,可以发现,CallbackRecord中的action的类型为Runnable:
/**
* <p>Causes the Runnable to execute on the next animation time step.
* The runnable will be run on the user interface thread.</p>
*
* @param action The Runnable that will be executed.
*
* @see #postOnAnimationDelayed
* @see #removeCallbacks
*/
public void postOnAnimation(Runnable action) {
final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
attachInfo.mViewRootImpl.mChoreographer.postCallback(
Choreographer.CALLBACK_ANIMATION, action, null);
} else {
// Postpone the runnable until we know
// on which thread it needs to run.
getRunQueue().post(action);
}
}
post()方法中传入的Runnable类型的参数为mAnimationStarter:
private Runnable mAnimationStarter = new Runnable() {
@Override
public void run() {
startAnimation();
}
};
private final Choreographer.FrameCallback mFrameCallback = new Choreographer.FrameCallback() {
@Override
public void doFrame(long frameTimeNanos) {
doAnimationFrame(getProvider().getFrameTime());
// 如果还有动画回调对象注册,也就是动画没有执行完,会继续请求下一个VSYNC信号,从而稳定的进行动画
if (mAnimationCallbacks.size() > 0) {
getProvider().postFrameCallback(this);
}
}
};
private void doAnimationFrame(long frameTime) {
long currentTime = SystemClock.uptimeMillis();
final int size = mAnimationCallbacks.size();
for (int i = 0; i < size; i++) {
final AnimationFrameCallback callback = mAnimationCallbacks.get(i);
if (callback == null) {
continue;
}
if (isCallbackDue(callback, currentTime)) {
// 核心逻辑,这一块就执行到了ValueAnimation或者是AnimationSet模块中的doAnimation,这个就需要看使用了哪一种Animation
callback.doAnimationFrame(frameTime);
if (mCommitCallbacks.contains(callback)) {
getProvider().postCommitCallback(new Runnable() {
@Override
public void run() {
commitAnimationFrame(callback, getProvider().getFrameTime());
}
});
}
}
}
cleanUpList();
}