[01 介绍&初始化]
从 Systrace 的角度来看 Choreogrepher 的工作流程
以滑动桌面为例子,我们先看一下从左到右滑动桌面的一个完整的预览图(App 进程),可以看到 Systrace 中从左到右,每一个绿色的帧都表示一帧,表示最终我们可以手机上看到的画面
- 图中每一个灰色的条和白色的条宽度是一个 Vsync 的时间,也就是 16.6ms
- 每一帧处理的流程:接收到 Vsync 信号回调-> UI Thread –> RenderThread –> SurfaceFlinger(图中未显示)
- UI Thread 和 RenderThread 就可以完成 App 一帧的渲染,渲染完的 Buffer 抛给 SurfaceFlinger 去合成,然后我们就可以在屏幕上看到这一帧了
- 可以看到桌面滑动的每一帧耗时都很短(Ui Thread 耗时 + RenderThread 耗时),但是由于 Vsync 的存在,每一帧都会等到 Vsync 才会去做处理
有了上面这个整体的概念,我们将 UI Thread 的每一帧放大来看,看看 Choreogrepher 的位置以及 Choreogrepher 是怎么组织每一帧的
[简介]
Choreographer 编舞者。统一动画、输入和绘制时机 Choreographer 的作用,主要是配合 Vsync ,给上层 App 的渲染提供一个稳定的 Message 处理的时机,即 Vsync 到来的时候 ,系统通过对 Vsync 信号周期的调整,来控制每一帧绘制操作的时机。
Choreographer 扮演 Android 渲染链路中承上启下的角色。
- 承上:负责接收和处理 App 的各种更新消息和回调,等到 Vsync 到来的时候统一处理。比如集中处理 Input(主要是 Input 事件的处理) 、Animation(动画相关)、Traversal(包括 measure、layout、draw 等操作) ,判断卡顿掉帧情况,记录 CallBack 耗时等
- 启下:负责请求和接收 Vsync 信号。接收 Vsync 事件回调(通过 FrameDisplayEventReceiver.onVsync );请求 Vsync(FrameDisplayEventReceiver.scheduleVsync) .
[Choreographer 的工作流程]
-
Choreographer初始化
- 初始化 FrameHandler ,绑定 主线程的Looper
- 初始化 FrameDisplayEventReceiver ,与 SurfaceFlinger 建立通信用于接收和请求 Vsync
- 初始化 CallBackQueues
-
SurfaceFlinger 的 appEventThread 唤醒发送 Vsync ,Choreographer 回调 FrameDisplayEventReceiver.onVsync , 进入 SurfaceFlinger 的主处理函数 doFrame
-
Choreographer.doFrame 计算掉帧逻辑
-
doFrame分别处理五个callback。input,animation,insets animation,traversal(traversal-draw 中 UIThread 与 RenderThread 同步数据),commit
-
RenderThread 处理绘制数据,真正进行渲染
-
将渲染好的 Buffer swap 给 SurfaceFlinger 进行合成
[源码分析]
[Choreographer初始化]
在 Activity 启动过程,执行完 onResume 后,会调用 Activity.makeVisible(),然后再调用到 addView(), 层层调用会进入如下方法
ActivityThread.handleResumeActivity(IBinder, boolean, boolean, String) (android.app)
-->WindowManagerImpl.addView(View, LayoutParams) (android.view)
-->WindowManagerGlobal.addView(View, LayoutParams, Display, Window) (android.view)
-->ViewRootImpl.ViewRootImpl(Context, Display) (android.view)
public ViewRootImpl(Context context, Display display) {
......
mChoreographer = Choreographer.getInstance();
......
}
Choreographer 的单例初始化
- 绘制操作需要放到主线程操作, 故将主线程的looper作为参数构造Choreographer.
- 当其有调度/绘制请求时, 向这个looper sendMessage. 等待主线程调度.
// Thread local storage for the choreographer.
private static final ThreadLocal<Choreographer> sThreadInstance =
new ThreadLocal<Choreographer>() {
@Override
protected Choreographer initialValue() {
// 获取当前线程的 Looper, 即主线程的looper.
Looper looper = Looper.myLooper();
......
// 构造 Choreographer 对象
Choreographer choreographer = new Choreographer(looper, VSYNC_SOURCE_APP);
if (looper == Looper.getMainLooper()) {
mMainInstance = choreographer;
}
return choreographer;
}
};
Choreographer 的构造函数
- looper为主线程的looper,mHandler用作向主线程sendMessage.
- USE_VSYNC默认为true, 即使用垂直刷新.
- 每个type的CallBack放在对应的CallbackQueue中.
private Choreographer(Looper looper, int vsyncSource) {
mLooper = looper;
// 1. 初始化 FrameHandler
mHandler = new FrameHandler(looper);
// 2. 初始化 DisplayEventReceiver
mDisplayEventReceiver = USE_VSYNC
? new FrameDisplayEventReceiver(looper, vsyncSource)
: null;
mLastFrameTimeNanos = Long.MIN_VALUE;
mFrameIntervalNanos = (long)(1000000000 / getRefreshRate());
//3. 初始化 CallbacksQueues
mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1];
for (int i = 0; i <= CALLBACK_LAST; i++) {
mCallbackQueues[i] = new CallbackQueue();
}
......
}
FrameHandler
private final class FrameHandler extends Handler {
public FrameHandler(Looper looper) {
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://请求 Vsync
doScheduleVsync();
break;
case MSG_DO_SCHEDULE_CALLBACK://处理 Callback, 最终会请求vsync
doScheduleCallback(msg.arg1);
break;
}
}
}
[FrameDisplayEventReceiver介绍]
Vsync 的注册、申请、接收都是通过 FrameDisplayEventReceiver 这个类,所以可以先简单介绍一下。 FrameDisplayEventReceiver 继承 DisplayEventReceiver , 有三个比较重要的方法
-
onVsync – Vsync 信号回调
- onVsync()过程是通过FrameHandler向主线程Looper发送了一个自带callback的消息,此处callback为FrameDisplayEventReceiver。 当主线程Looper执行到该消息时,则调用FrameDisplayEventReceiver.run()方法.
-
run – 执行 doFrame
-
scheduleVsync – 请求 Vsync 信号
private final class FrameDisplayEventReceiver extends DisplayEventReceiver implements Runnable {
......
@Override
public void onVsync(long timestampNanos, long physicalDisplayId, int frame) {
......
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);
}
@Override
public void run() {
mHavePendingVsync = false;
doFrame(mTimestampNanos, mFrame);
}
public void scheduleVsync() {
......
nativeScheduleVsync(mReceiverPtr);
......
}
}
Choreographer 中 Vsync 的注册
FrameDisplayEventReceiver 是通过什么方式在 Vsync 信号到来的时候回调 onVsync 呢?答案是 FrameDisplayEventReceiver 继承了DisplayEventReceiver, 初始化的时候,最终通过监听文件句柄的形式,其对应的初始化流程为:
android/view/Choreographer.java
private Choreographer(Looper looper, int vsyncSource) {
mLooper = looper;
mDisplayEventReceiver = USE_VSYNC
? new FrameDisplayEventReceiver(looper, vsyncSource)
: null;
......
}
public FrameDisplayEventReceiver(Looper looper, int vsyncSource) {
super(looper, vsyncSource);
}
android/view/DisplayEventReceiver.java
public DisplayEventReceiver(Looper looper, int vsyncSource) {
......
mMessageQueue = looper.getQueue();
mReceiverPtr = nativeInit(new WeakReference<DisplayEventReceiver>(this), mMessageQueue,
vsyncSource);
}
android_view_DisplayEventReceiver.nativeInit()->NativeDisplayEventReceiver()->android_view_DisplayEventReceiver.initialize()
status_t NativeDisplayEventReceiver::initialize() {
//mReceiver为DisplayEventReceiver类型
status_t result = mReceiver.initCheck();
...
//监听mReceiver的所获取的文件句柄。
int rc = mMessageQueue->getLooper()->addFd(mReceiver.getFd(), 0, Looper::EVENT_INPUT,
this, NULL);
...
return OK;
}
[Choreographer 处理一帧的逻辑]
Choreographer 处理绘制的逻辑核心在 Choreographer.doFrame 函数中,FrameDisplayEventReceiver.onVsync post 了自己,其 run 方法直接调用了 doFrame 开始一帧的逻辑处理
doFrame 函数主要做下面几件事
- 计算掉帧逻辑
- 记录帧绘制信息
- 执行 CALLBACK_INPUT、CALLBACK_ANIMATION、CALLBACK_INSETS_ANIMATION、CALLBACK_TRAVERSAL、CALLBACK_COMMIT
困惑解决:
doFrame的时机? mHandler和mCallbackQueues的关系? mHandler各个操作的意义? 为什么要向mHandler传递参数也要向queue中addCallback?
- 绘制操作全都在主线程上执行,即looper线程.Choreographer初始化时, 会传入主线程的looper.
- 所以, 当需要调度时, 若处于looper线程就直接执行, 如果没有还需要
mHandler.sendMessage()等待主线程调度. - 当有绘图需要时,
mCallbackQueues[callbackType].addCallbackLocked. 当vsync来临时, 向loopermHandler.sendMessage()然后等待主线程的调度执行, 执行FrameHandler的run()->doFrame()方法.
if (isRunningOnLooperThreadLocked()) {
//当运行在Looper线程,则立刻调度vsync
scheduleVsyncLocked();
} else {
//否则,发送消息到UI线程
Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
msg.setAsynchronous(true);
mHandler.sendMessageAtFrontOfQueue(msg);
}
这段代码, 当运行在Looper线程,则立刻调度scheduleVsyncLocked(); 当运行在其他线程,则通过发送一个消息到Looper线程,然后再执行scheduleVsyncLocked();
- 每调用一次scheduleFrameLocked() (用来申请vsync),则mFrameScheduled=true,可进入doFrame()方法体内部,执行完doFrame()并设置mFrameScheduled=false;
- 动画消息是
postFrameCallback()涉及其他操作,最终执行frameCallBack.doFrame()方法 , 其他操作是postCallback(), 最终执行run方法
public void run(long frameTimeNanos) {
if (token == FRAME_CALLBACK_TOKEN) {
((FrameCallback)action).doFrame(frameTimeNanos);
} else {
((Runnable)action).run();
}
}
[02 执行过程]
举例分析
以图为例, 分析执行过程
-
1.
postCallback(runnable1)→scheduleFrameLocked()(将mFrameScheduled设置为true,并向mCallbackQueues添加Callback) →scheduleVsync()(最终调用nativeScheduleVsync向appEventThread发起connection,请求Vsync) -
2.frameTimeNanos1 时刻收到 VSync,向主线程 Looper 队列插入一个 msg, 等待主线程来执行.
-
3.Looper 取出 2 的 msg,调用 onVsync(frameTimeNanos1) →
doFrame(frameTimeNanos1)(将mFrameScheduled设置为true)- 3.1) 判断没有掉帧
- 3.2) doCallbacks 调用
runnable1.run()对于animation来说调用runnable1.doFrame()
-
4.postCallback(runnable2) → scheduleFrameLocked() → scheduleVsync()
-
5.postCallback(runnable3) scheduleFrameLocked() 判断 mFrameScheduled == true 直接 return,所以并不会调用 scheduleVsync()
-
6.frameTimeNanos2 时刻收到 VSync,往 Looper 队列插入一个 msg
-
7.Looper 取出 6 的 msg,调用 onVsync(frameTimeNanos2) → doFrame(frameTimeNanos2)
- 7.1 虽然有延迟,但是延迟没有超过 16 毫秒,判断没有掉帧
- 7.2 doCallbacks 调用 runnable2.run() 和 runnable3.run()
-
8.非 UI 线程 postCallback(runnable4) 往 Looper 队列插入一个 msg, 等待主线程来执行.
-
9.frameTimeNanos3 时刻接收不到 VSync,因为自上次收到 VSync 后,未调用过 scheduleVsync()
-
10.Looper 取出 8 的 msg,调用 scheduleFrameLocked → scheduleVsync()
-
11.frameTimeNanos4 时刻收到 VSync,往 Looper 队列插入一个 msg
-
12.Looper 取出 11 的 msg,调用 onVsync(frameTimeNanos4) → doFrame(当前时间,即最后一个doFrame开始的地方)
-
12.1 延迟超过 16 毫秒,判断掉帧
-
12.2 修正 frameTimeNanos(frameTimeNanos = startNanos - lastFrameOffset)frameTimeNanos = frameTimeNanos5
-
12.3 doCallbacks 调用 runnable4.run()
-
流程图:
特点
- 绘制操作全都在主线程上执行,即looper线程.Choreographer初始化时, 会传入主线程的looper.所以, 当需要调度时, 若处于looper线程就直接执行, 如果没有还需要
mHandler.sendMessage()等待主线程调度. - 当有绘图需要时,
mCallbackQueues[callbackType].addCallbackLocked. 当vsync来临时, 向loopermHandler.sendMessage()然后等待主线程的调度执行, 执行FrameHandler的run()->doFrame()方法.
if (isRunningOnLooperThreadLocked()) {
//当运行在Looper线程,则立刻调度vsync
scheduleVsyncLocked();
} else {
//否则,发送消息到UI线程
Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
msg.setAsynchronous(true);
mHandler.sendMessageAtFrontOfQueue(msg);
}
这段代码, 当运行在Looper线程,则立刻调度scheduleVsyncLocked(); 当运行在其他线程,则通过发送一个消息到Looper线程,然后再执行scheduleVsyncLocked();
- 每调用一次scheduleFrameLocked() (用来申请vsync),则mFrameScheduled=true,可进入doFrame()方法体内部,执行完doFrame()并设置mFrameScheduled=false;
- 动画消息是
postFrameCallback()涉及其他操作,最终执行frameCallBack.doFrame()方法 , 其他操作是postCallback(), 最终执行run方法
public void run(long frameTimeNanos) {
if (token == FRAME_CALLBACK_TOKEN) {
((FrameCallback)action).doFrame(frameTimeNanos);
} else {
((Runnable)action).run();
}
}
Choreographer 处理一帧的逻辑
Choreographer 处理绘制的逻辑核心在 Choreographer.doFrame 函数中,FrameDisplayEventReceiver.onVsync post 了自己,其 run 方法直接调用了 doFrame 开始一帧的逻辑处理
doFrame 函数主要做下面几件事
- 计算掉帧逻辑
- 记录帧绘制信息
- 执行 CALLBACK_INPUT、CALLBACK_ANIMATION、CALLBACK_INSETS_ANIMATION、CALLBACK_TRAVERSAL、CALLBACK_COMMIT
计算掉帧逻辑
- Choreographer.doFrame 的掉帧检测比较简单,从下图可以看到,Vsync 信号到来的时候会标记一个 start_time ,执行 doFrame 的时候标记一个 end_time ,这两个时间差就是 Vsync 处理时延,也就是掉帧
- SKIPPED_FRAME_WARNING_LIMIT默认值为30
void doFrame(long frameTimeNanos, int frame) {
final long startNanos;
synchronized (mLock) {
......
long intendedFrameTimeNanos = frameTimeNanos; //Vsync来临的时间,也就是原本计划的绘帧时间点
startNanos = System.nanoTime();
final long jitterNanos = startNanos - frameTimeNanos; //
if (jitterNanos >= mFrameIntervalNanos) {
final long skippedFrames = jitterNanos / mFrameIntervalNanos;
//当掉帧个数超过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 % mFrameIntervalNanos;
//Frame time appears to be going backwards. May be due to a previously skipped frame. Waiting for next vsync.
frameTimeNanos = startNanos - lastFrameOffset; //对齐帧的时间间隔, 即与Vsync信号对齐
}
if (frameTimeNanos < mLastFrameTimeNanos) {
scheduleVsyncLocked();
return;
}
mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos);
mFrameScheduled = false;
mLastFrameTimeNanos = frameTimeNanos;//记录上次Vsync申请的时间
......
}
......
}
记录帧绘制信息
- Choreographer 中 FrameInfo 来负责记录帧的绘制信息,doFrame 执行的时候,会把每一个关键节点的绘制时间记录下来,我们使用 dumpsys gfxinfo 就可以看到。当然 Choreographer 只是记录了一部分,剩余的部分在 hwui 那边来记录。
- doFrame 函数记录从 Vsync time 到 markPerformTraversalsStart 的时间
- Davey日志
void doFrame(long frameTimeNanos, int frame) {
......
mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos);
// 处理 CALLBACK_INPUT Callbacks
mFrameInfo.markInputHandlingStart();
// 处理 CALLBACK_ANIMATION Callbacks
mFrameInfo.markAnimationsStart();
// 处理 CALLBACK_INSETS_ANIMATION Callbacks
// 处理 CALLBACK_TRAVERSAL Callbacks
mFrameInfo.markPerformTraversalsStart();
// 处理 CALLBACK_COMMIT Callbacks
......
}
执行 Callbacks
void doFrame(long frameTimeNanos, int frame) {
......
// 处理 CALLBACK_INPUT Callbacks
doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);
// 处理 CALLBACK_ANIMATION Callbacks
doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
// 处理 CALLBACK_INSETS_ANIMATION Callbacks
doCallbacks(Choreographer.CALLBACK_INSETS_ANIMATION, frameTimeNanos);
// 处理 CALLBACK_TRAVERSAL Callbacks
doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
// 处理 CALLBACK_COMMIT Callbacks
doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos);
......
}
Input 回调调用
input callback 一般是android.view.ViewRootImpl$ConsumeBatchedInputRunnable
android/view/ViewRootImpl.java
final class ConsumeBatchedInputRunnable implements Runnable {
@Override
public void run() {
doConsumeBatchedInput(mChoreographer.getFrameTimeNanos());
}
}
void doConsumeBatchedInput(long frameTimeNanos) {
if (mConsumeBatchedInputScheduled) {
mConsumeBatchedInputScheduled = false;
if (mInputEventReceiver != null) {
if (mInputEventReceiver.consumeBatchedInputEvents(frameTimeNanos)
&& frameTimeNanos != -1) {
scheduleConsumeBatchedInput();
}
}
doProcessInputEvents();
}
}
Traversal 调用栈
callback一般是android.view.ViewRootImpl$TraversalRunnable
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
//为了提高优先级,先 postSyncBarrier
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
mChoreographer.postCallback(//向mChoreographer发送消息
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
}
}
final class TraversalRunnable implements Runnable {
@Override
public void run() {
// 真正开始执行 measure、layout、draw
doTraversal();
}
}
void doTraversal() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
// 这里把 SyncBarrier remove
mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
// 真正开始
performTraversals();
}
}
private void performTraversals() {
// measure 操作
if (focusChangedDueToTouchMode || mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight() || contentInsetsChanged || updatedConfiguration) {
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
}
// layout 操作
if (didLayout) {
performLayout(lp, mWidth, mHeight);
}
// draw 操作
if (!cancelDraw && !newSurface) {
performDraw();
}
}
Choreographer请求下一帧的 Vsync
由于动画、滑动、Fling 这些操作的存在,我们需要一个连续的、稳定的帧率输出机制。这就涉及到了 Vsync 的请求逻辑,在连续的操作,比如动画、滑动、Fling 这些情况下,每一帧的 doFrame 的时候,都会根据情况触发下一个 Vsync 的申请,这样我们就可以获得连续的 Vsync 信号。
我们下面以 Animation 为例,看看 Animation 是如何驱动下一个 Vsync ,来持续更新画面的
ObjectAnimator 动画驱动逻辑
android/animation/ObjectAnimator.java
public void start() {
super.start();
}
android/animation/ValueAnimator.java
private void start(boolean playBackwards) {
......
addAnimationCallback(0); // 动画 start 的时候添加 Animation Callback
......
}
private void addAnimationCallback(long delay) {
......
getAnimationHandler().addAnimationFrameCallback(this, delay);
}
android/animation/AnimationHandler.java
public void addAnimationFrameCallback(final AnimationFrameCallback callback, long delay) {
if (mAnimationCallbacks.size() == 0) {
// post FrameCallback, 向mChoreographer post
getProvider().postFrameCallback(mFrameCallback);
}
......
}
// 这里的 mFrameCallback 回调 doFrame,里面 post了自己
private final Choreographer.FrameCallback mFrameCallback = new Choreographer.FrameCallback() {
@Override
public void doFrame(long frameTimeNanos) {
doAnimationFrame(getProvider().getFrameTime());
if (mAnimationCallbacks.size() > 0) {
// post 自己
getProvider().postFrameCallback(this);
}
}
};
调用 postFrameCallback 会走到 mChoreographer.postFrameCallback ,这里就会触发 Choreographer 的 Vsync 请求逻辑
android/animation/AnimationHandler.java
public void postFrameCallback(Choreographer.FrameCallback callback) {
mChoreographer.postFrameCallback(callback);
}
android/view/Choreographer.java
scheduleFrameLocked是一个很重要的操作, 用于请求 Vsync- scheduleFrameLocked ->scheduleVsyncLocked-> mDisplayEventReceiver.scheduleVsync ->nativeScheduleVsync
- 如果没有到执行时间, 向主looper,sendMessage(MSG_DO_SCHEDULE_CALLBACK), 最后也是执行
scheduleFrameLocked mFrameScheduled是一个很重要的变量, 他默认为true,
private void postCallbackDelayedInternal(int callbackType,
Object action, Object token, long delayMillis) {
synchronized (mLock) {
final long now = SystemClock.uptimeMillis();
final long dueTime = now + delayMillis;
//向mCallbackQueues[callbackType]添加相应类型的callBack, 等到Vsync来临时执行.
mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
if (dueTime <= now) {
// 请求 Vsync
scheduleFrameLocked(now);
} else {
Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
msg.arg1 = callbackType;
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, dueTime);
}
}
}
Choreographer.scheduleFrameLocked()
- 注释说明问题, choreographer的绘制操作都放在主线程.
- 这段代码, 当运行在
Looper线程,则立刻调度scheduleVsyncLocked(); 当运行在其他线程,则通过发送一个消息到Looper线程,然后再执行scheduleVsyncLocked();最终调用nativeScheduleVsync向appEventThread发起connection,请求Vsync.
private void scheduleFrameLocked(long now) {
if (!mFrameScheduled) {
mFrameScheduled = true;
if (USE_VSYNC && !sIsNextFrameAtFront) {
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);
}
}
}
}
doFrame()
- 每调用一次scheduleFrameLocked() (用来申请vsync),则mFrameScheduled=true,可进入doFrame()方法体内部,执行完doFrame()并设置mFrameScheduled=false;
- 就像调度器, 使doFrame和请求Vsync有序执行. 一帧之内若出现两次postCallback, 则不会申请第二次Vsync, 因为则mFrameScheduled是false.
void doFrame(long frameTimeNanos, int frame) {
final long startNanos;
synchronized (mLock) {
if (!mFrameScheduled) {
return; // no work to do
}
}
}
参考: