Choreographer met

“This is the 11th day of my participation in the Gwen Challenge in November. See details: The Last Gwen Challenge in 2021”

The View calls requestLayout() to initiate a UI redraw, and New Runnable is thrown into Choreographer’s message queue, which calls SurfaceFlinger to request the next Vsync signal, The SurfaceFlinger will send messages to Choreographer to process the tasks in the message queue when the next Vsync signal comes.

1. Initialization

In the Activity startup process, handleResumeActivity

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

Call the addView method of WindowManagerImpl

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

MGlobal is a singleton object for Windows ManagerGlobal.

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

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

Root is an instance object of ViewRootImpl, and Choreographer singleton objects are created within the constructor of ViewRootImpl.

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

This has outlined Choreographer’s initialization invocation flow and continues with the introduction to Choreographer’s initialization.

public static Choreographer getInstance(a) {
    return sThreadInstance.get();
}
Copy the code

2. Choreographer initialization

Singleton initialization of Choreographer

private static final ThreadLocal<Choreographer> sThreadInstance =
        new ThreadLocal<Choreographer>() {
    @Override
    protected Choreographer initialValue(a) {
        Looper looper = Looper.myLooper();
        if (looper == null) {
            throw new IllegalStateException("The current thread must have a looper!");
        }
        // Create Choreographer objects
        Choreographer choreographer = new Choreographer(looper, VSYNC_SOURCE_APP);
        if (looper == Looper.getMainLooper()) {
            mMainInstance = choreographer;
        }
        returnchoreographer; }};Copy the code

ThreadLocal is created before the initialization process to ensure that Choreographer threads singleton, typically the main thread.

Much of Choreographer’s task scheduling is through the FrameHandler, so the thread on which the processor is located must have Looper.

Choreographer constructor method:

private Choreographer(Looper looper, int vsyncSource) {
    mLooper = looper;
    // 1. Initialize FrameHandler
    mHandler = new FrameHandler(looper);
    // 2. Initialize DisplayEventReceiver
    mDisplayEventReceiver = USE_VSYNC
        ? new FrameDisplayEventReceiver(looper, vsyncSource)
        : null;
    // The point in time when the last frame was drawn
    mLastFrameTimeNanos = Long.MIN_VALUE;
    // Interval of each frame, 16.6ms
    mFrameIntervalNanos = (long) (1000000000 / getRefreshRate());
    Initialize the 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));
}
Copy the code

Three main things are done during initialization:

  1. Initialize the FrameHandler and bind the Looper response time.
  2. Initialize FrameDisplayEventReceiver, scheduling Vsync and SurfaceFlinger response.
  3. Initialize the CallbacksQueues, where the callbacks for task scheduling are placed.

FrameHandler

FrameHandler implements the core methods doFrame() and scheduling Vsync, described in the comments.

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:// Start rendering the next frame
                doFrame(System.nanoTime(), 0);
                break;
            case MSG_DO_SCHEDULE_VSYNC:/ / request Vsync
                doScheduleVsync();
                break;
            case MSG_DO_SCHEDULE_CALLBACK:/ / Callback processing
                doScheduleCallback(msg.arg1);
                break; }}}Copy the code

FrameDisplayEventReceiver

The onVsync method is called back after the Vsync signal is requested. There are three important methods:

  • OnVsync () : responds to the Vsync signal
  • ScheduleVsync () : schedules Vsync signals
  • Run () : executes doFrame(), which computes the frame, responds to Input, Animation, Traversal(measure/layout/draw), and 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 signal callback
    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.000001 f)
                    + " 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 execution
    @Override
    public void run(a) {
        mHavePendingVsync = false; doFrame(mTimestampNanos, mFrame); }}Copy the code