android 图形系统之Choreographer

991 阅读2分钟

在学习Choreographer之前我们应该知道view的一些知识:

界面变化原因是view数据发生了变化,view数据变化的原因有:

  1. 创建了一个新的Window。创建一个新的Window一般来说也就意味着新的Activity的启动,加载一个XML布局到的decorView中。源码解读
  2. 添加了一个新的View。通过调用ViewGroup#addView方法添加一个新的View到ViewGroup
  3. 更新了已有的View。 以上的问题都会引起ViewRootImpl的requestLayout调用。

Choreographer 源码解析

以下源码解析来自Android api:29

从ViewRootImpl的requestLayout开始:

 @Override
    public void requestLayout() {
        if (!mHandlingLayoutInLayoutRequest) {
            checkThread();
            mLayoutRequested = true;//是否是measure和layout布局
            scheduleTraversals();
        }
    }
  
  @UnsupportedAppUsage
    void scheduleTraversals() {
        if (!mTraversalScheduled) { //同一帧不多次调用
            mTraversalScheduled = true;
            mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();//注解1
            //Choreographer回调,执行绘制操作
            mChoreographer.postCallback(
                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
           
        }
    }

注解1: postSyncBarrier:发送屏障消息,使handler的除异步消息其他消息的进入阻塞状态,也就意味着其他ui消息无法被处理。

mChoreographer发送一个回调函数。mChoreographer是在ViewRootImpl构造方法中被初始化

public ViewRootImpl(Context context, Display display) {
    
    mChoreographer = Choreographer.getInstance();//是个线程间单例
}

/**
     * Gets the choreographer for the calling thread.  Must be called from
     * a thread that already has a {@link android.os.Looper} associated with it.
     *
     * @return The choreographer for this thread.
     * @throws IllegalStateException if the thread does not have a looper.
     */
    public static Choreographer getInstance() {
        return sThreadInstance.get();
    }
    
    
    // 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);
                }
            };

每一个looper线程都有一个独立的Choreographer,每个Choreographer处理所在线程的事件。

    private Choreographer(Looper looper, int vsyncSource) {
        mLooper = looper;
        mHandler = new FrameHandler(looper);
        mDisplayEventReceiver =  
                ? new FrameDisplayEventReceiver(looper, vsyncSource)
                : null;
        mLastFrameTimeNanos = Long.MIN_VALUE;

        mFrameIntervalNanos = (long)(1000000000 / getRefreshRate());

        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));
    }

初始化了三个东西:

  • mHandler:用于处理延时消息
  • mDisplayEventReceiver:处理Vsync信号脉冲(请求和接受)
  • mCallbackQueues 大小为5的数组,数组头为链表头,(数组+链表)
    1. CALLBACK_INPUT 输入事件
    2. CALLBACK_INSETS_ANIMATION 插图动画
    3. CALLBACK_ANIMATION 动画
    4. CALLBACK_TRAVERSAL 视图绘制
    5. CALLBACK_COMMIT 提交

Choreographer的postCallback流程图如下:

两种callback都都会回调到postCallbackDelayedInternal:

  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].addCallbackLocked(dueTime, action, token);

            if (dueTime <= now) {
                scheduleFrameLocked(now);
            } else {
                Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
                msg.arg1 = callbackType;
                msg.setAsynchronous(true);
                mHandler.sendMessageAtTime(msg, dueTime);
            }
        }
    }

此方法处理两件事:1.将事件加入CallbackQueues中以对应type为头的链表中。2.计算时间

private void scheduleFrameLocked(long now) {
        if (!mFrameScheduled) {
            mFrameScheduled = true;
            if (USE_VSYNC) {
                ...
                if (isRunningOnLooperThreadLocked()) {
                    scheduleVsyncLocked();
                } else {
                    Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
                    msg.setAsynchronous(true);
                    mHandler.sendMessageAtFrontOfQueue(msg);
                }
            } else {
                ....
                mHandler.sendMessageAtTime(msg, nextFrameTime);
            }
        }
    }

判断是否使用USE_VSYNC ,这个是系统决定。这里只分析使用Vsync的情况: 请求VSYNC信号脉冲,这一步会回调到native层,native中会将ui元数据对SurfaceFlinger服务进行数据处理,最后将会回调到FrameDisplayEventReceiver的onVsync方法,然后回调doFrame方法。

 @UnsupportedAppUsage
    void doFrame(long frameTimeNanos, int frame) {
        final long startNanos;
        synchronized (mLock) {
            if (!mFrameScheduled) {
                return; // no work to do
            }

           ...

            long intendedFrameTimeNanos = frameTimeNanos;
            startNanos = System.nanoTime();
            final long jitterNanos = startNanos - frameTimeNanos;//计算时间差
            if (jitterNanos >= mFrameIntervalNanos) {
                //时差大与16ms
                //处理帧对齐
            }

            if (frameTimeNanos < mLastFrameTimeNanos) {
                //小于一屏的刷新时间
            }
            ...
        }

        try {
            Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Choreographer#doFrame");
            AnimationUtils.lockAnimationClock(frameTimeNanos / TimeUtils.NANOS_PER_MS);

            mFrameInfo.markInputHandlingStart();
            doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);

            mFrameInfo.markAnimationsStart();
            doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
            doCallbacks(Choreographer.CALLBACK_INSETS_ANIMATION, frameTimeNanos);

            mFrameInfo.markPerformTraversalsStart();
            doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);

            doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos);
        } finally {
            AnimationUtils.unlockAnimationClock();
            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
        }
        ...
    }

doFrame中做了两件事:

  1. 判断VSYNC信号脉冲返回时与发送时的时间差:
    • 如果大与屏幕刷新率 帧对齐;
    • 如果小于一次的屏幕刷新时间,重新申请VSYNC脉冲。
  2. 回调各种刚开始时记录的callback。

执行doCallback事件其实就是执行,mTraversalRunnable。

总结

  1. ViewRootImpl#requestLayout为Choreographer发送一个callback事件,Choreographer通过请求VSYNC信号脉冲来处理callback事件。
  2. 系统每16ms发送一次VSYNC信号脉冲,当ViewRootImpl#requestLayout的两次调用之间

View绘制流程总括