Choreographer

385 阅读7分钟

[01 介绍&初始化]

从 Systrace 的角度来看 Choreogrepher 的工作流程

以滑动桌面为例子,我们先看一下从左到右滑动桌面的一个完整的预览图(App 进程),可以看到 Systrace 中从左到右,每一个绿色的帧都表示一帧,表示最终我们可以手机上看到的画面

  1. 图中每一个灰色的条和白色的条宽度是一个 Vsync 的时间,也就是 16.6ms
  2. 每一帧处理的流程:接收到 Vsync 信号回调-> UI Thread –> RenderThread –> SurfaceFlinger(图中未显示)
  3. UI Thread 和 RenderThread 就可以完成 App 一帧的渲染,渲染完的 Buffer 抛给 SurfaceFlinger 去合成,然后我们就可以在屏幕上看到这一帧了
  4. 可以看到桌面滑动的每一帧耗时都很短(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来临时, 向looper mHandler.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来临时, 向looper mHandler.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
            }
        }
}

参考: