Choreographer初识

691 阅读2分钟

「这是我参与11月更文挑战的第11天,活动详情查看:2021最后一次更文挑战

View调用requestLayout()发起UI重绘,new Runnable丢到Choreographer的消息队列,Choreographer向SurfaceFlinger取请求下一个Vsync信号,SurfaceFlinger在下一个Vsync信号来的时候会向Choreographer发送消息去处理消息队列中的任务。

1.初始化

在Activity的启动流程中,handleResumeActivity

 if (a.mVisibleFromClient) {
     if (!a.mWindowAdded) {
         a.mWindowAdded = true;
         wm.addView(decor, l);
     } else {
         a.onWindowAttributesChanged(l);
     }
 }

调用WindowManagerImpl的addView方法

mGlobal.addView(view, params, mContext.getDisplayNoVerify(), mParentWindow,
                mContext.getUserId());

mGlobal是WindowManagerGlobal的单例对象。

/frameworks/base/core/java/android/view/WindowManagerGlobal.java$addView

root = new ViewRootImpl(view.getContext(), display);

root是ViewRootImpl的实例对象,在ViewRootImpl的构造方法中会创建Choreographer的单例对象。

public ViewRootImpl(Context context, Display display, IWindowSession session,
            boolean useSfChoreographer) {
    //...
    mChoreographer = useSfChoreographer
        ? Choreographer.getSfInstance() : Choreographer.getInstance();
    //...
}

上面简述了Choreographer的初始化调用流程,紧接着继续介绍Choreographer的初始化。

public static Choreographer getInstance() {
    return sThreadInstance.get();
}

2. Choreographer初始化

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 choreographer = new Choreographer(looper, VSYNC_SOURCE_APP);
        if (looper == Looper.getMainLooper()) {
            mMainInstance = choreographer;
        }
        return choreographer;
    }
};

在初始化过程前会创建ThreadLocal,从而保证Choreographer线程单例,一般是主线程。

Choreographer的很多任务调度是通过FrameHandler,因此器所在线程必须有Looper。

Choreographer构造方法:

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;
    //每一帧的间隔,16.6ms
    mFrameIntervalNanos = (long) (1000000000 / getRefreshRate());
    //3. 初始化 CallbacksQueues
    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));
}

在初始化的过程中主要做了三件事:

  1. 初始化FrameHandler,绑定Looper响应时间。
  2. 初始化FrameDisplayEventReceiver,与SurfaceFlinger响应调度Vsync。
  3. 初始化CallbacksQueues,任务调度的回调都是放到这里。

FrameHandler

FrameHandler执行了核心方法doFrame()和调度Vsync,具体方法描述请参考注释。

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
                doScheduleCallback(msg.arg1);
                break;
        }
    }
}

FrameDisplayEventReceiver

请求返回Vsync信号后,会回调onVsync方法 这里面有三个重要方法:

  • onVsync():响应 Vsync 信号
  • scheduleVsync():调度 Vsync 信号
  • run():执行 doFrame(),doFrame() 内部会做计算掉帧、响应 Input、Animation、Traversal(measure/layout/draw)、Commit
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);
    }
​
    @Override
    // Vsync信号的回调
    public void onVsync(long timestampNanos, long physicalDisplayId, int frame) {
        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;
        }
​
        mTimestampNanos = timestampNanos;
        mFrame = frame;
        Message msg = Message.obtain(mHandler, this);   //public void run() 
        msg.setAsynchronous(true);
        mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
    }
​
    //执行doFrame
    @Override
    public void run() {
        mHavePendingVsync = false;
        doFrame(mTimestampNanos, mFrame);
    }
}