Android Choreographer机制

一 概述

在分析 Choreographer 机制之前,同学们需要先了解一些关于 Android 显示系统的一些基础概念和背景。可以参考 Android图形显示系统1 概述

我们知道 Google 在 Android 4.1 系统中对 Android Display 系统进行了优化:在收到 VSync 信号后,将马上开始下一帧的渲染。即一旦收到 VSync 通知,CPU 和 GPU 就立刻开始计算,然后把数据写入 buffer。本篇文章重点分析 Choreographer,以及 Choreographer 与 Vsync 信号之间的交互。

  • Choreographer,意为舞蹈编导、编舞者。在这里就是指对 CPU/GPU 绘制的指导 —— 收到 VSync 信号才开始绘制,保证绘制拥有完整的 16.6ms,避免绘制的随机性
  • Choreographer,是一个 Java 类,包路径 android.view.Choreographer。类注释是 “协调动画、输入和绘图的计时”
  • 通常应用层不会直接使用 Choreographer,而是使用更高级的 API,例如动画和 View 绘制相关的 ValueAnimator.start()、View.invalidate() 等。
  • 业界一般通过 Choreographer 来监控应用的帧率

二 Choreographer启动流程

在 Activity 启动过程中,执行完 onResume 后,会调用 Activity.makeVisible(),然后再调用到 addView(), 层层调用会进入 ViewRootImpl 的构造方法:

public ViewRootImpl(Context context, Display display) {
    ......
    //这里获取Choreographer实例
    mChoreographer = Choreographer.getInstance();
    ......
}

2.1 getInstance

Choreographer.java

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

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

可知在 Choreographer 中使用到了 ThreadLocal。当前所在线程为 UI 线程,也就是常说的主线程。

2.2 创建Choreographer

private Choreographer(Looper looper, int vsyncSource) {
    mLooper = looper;
    //创建Handler对象,这个handler用于向主线程发送消息
    mHandler = new FrameHandler(looper);
    //创建用于接收VSync信号的对象
    mDisplayEventReceiver = USE_VSYNC ?
            new FrameDisplayEventReceiver(looper, vsyncSource) : null;
    mLastFrameTimeNanos = Long.MIN_VALUE;
    mFrameIntervalNanos = (long)(1000000000 / getRefreshRate());
    //创建回调对象,其中CALLBACK_LAST=4
    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));
}
  • mLastFrameTimeNanos:指上一次帧绘制时间点
  • mFrameIntervalNanos:帧间时长,一般等于16.7ms

2.3 创建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,即绘制过程
                    doFrame(System.nanoTime(), 0);
                    break;
                case MSG_DO_SCHEDULE_VSYNC:
                //申请VSYNC信号,例如当前需要绘制任务时
                    doScheduleVsync();
                    break;
                case MSG_DO_SCHEDULE_CALLBACK:
                //需要延迟的任务,最终还是执行上述两个事件
                    doScheduleCallback(msg.arg1);
                    break;
            }
        }
    }

2.4 创建FrameDisplayEventReceiver

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

//关键点:收到 Vsync 信号后的回调
        @Override
        public void onVsync(long timestampNanos, long physicalDisplayId, int frame) {
            // Post the vsync event to the Handler.
            // The idea is to prevent incoming vsync events from completely starving
            // the message queue.  If there are no messages in the queue with timestamps
            // earlier than the frame time, then the vsync event will be processed immediately.
            // Otherwise, messages that predate the vsync event will be handled first.
            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;
            //将本身作为 runnable 传入 msg, 发消息后会走 run(),即 doFrame(),也是异步消息
            Message msg = Message.obtain(mHandler, this);
            msg.setAsynchronous(true);
            mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
        }

        @Override
        public void run() {
            mHavePendingVsync = false;
            doFrame(mTimestampNanos, mFrame);
        }
}

2.4.1 DisplayEventReceiver

DisplayEventReceiver.java

public DisplayEventReceiver(Looper looper) {
        this(looper, VSYNC_SOURCE_APP, CONFIG_CHANGED_EVENT_SUPPRESS);
}

public DisplayEventReceiver(Looper looper, int vsyncSource, int configChanged) {
        if (looper == null) {
            throw new IllegalArgumentException("looper must not be null");
        }

        mMessageQueue = looper.getQueue();
        mReceiverPtr = nativeInit(new WeakReference<DisplayEventReceiver>(this), mMessageQueue,
                vsyncSource, configChanged);

        mCloseGuard.open("dispose");
}

经过 JNI 调用进入如下 Native 方法。

2.4.2 nativeInit

android_view_DisplayEventReceiver.cpp

static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,
        jobject messageQueueObj, jint vsyncSource, jint configChanged) {
    sp<MessageQueue> messageQueue =
        android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
    if (messageQueue == NULL) {
        jniThrowRuntimeException(env, "MessageQueue is not initialized.");
        return 0;
    }

    sp<NativeDisplayEventReceiver> receiver = new NativeDisplayEventReceiver(env,
            receiverWeak, messageQueue, vsyncSource, configChanged);
    //会调用到其父类 DisplayEventDispatcher 的 initialize 方法
    status_t status = receiver->initialize();
    if (status) {
        String8 message;
        message.appendFormat("Failed to initialize display event receiver.  status=%d", status);
        jniThrowRuntimeException(env, message.string());
        return 0;
    }
    // retain a reference for the object
    // 获取 DisplayEventReceiver 对象的引用
    receiver->incStrong(gDisplayEventReceiverClassInfo.clazz); 
    return reinterpret_cast<jlong>(receiver.get());
}

2.4.3 创建NativeDisplayEventReceiver

NativeDisplayEventReceiver::NativeDisplayEventReceiver(JNIEnv* env,
        jobject receiverWeak, const sp<MessageQueue>& messageQueue, jint vsyncSource,
        jint configChanged) :
        DisplayEventDispatcher(messageQueue->getLooper(),
                static_cast<ISurfaceComposer::VsyncSource>(vsyncSource),
                static_cast<ISurfaceComposer::ConfigChanged>(configChanged)),
        mReceiverWeakGlobal(env->NewGlobalRef(receiverWeak)),
        mMessageQueue(messageQueue) {
    ALOGV("receiver %p ~ Initializing display event receiver.", this);
}

NativeDisplayEventReceiver 继承于 DisplayEventDispatcher,而 DisplayEventDispatcher 又继承于 LooperCallback 对象,此处 mReceiverWeakGlobal 记录的是 Java 层 DisplayEventReceiver 对象的全局引用。

2.4.4 DisplayEventDispatcher.initialize

framework/base/libs/androidfw/DisplayEventDispatcher.cpp

status_t DisplayEventDispatcher::initialize() {
    status_t result = mReceiver.initCheck();
    if (result) {
        ALOGW("Failed to initialize display event receiver, status=%d", result);
        return result;
    }

    int rc = mLooper->addFd(mReceiver.getFd(), 0, Looper::EVENT_INPUT,
            this, NULL);
    if (rc < 0) {
        return UNKNOWN_ERROR;
    }
    return OK;
}

从代码中可以看到,是把 mReceiver 的文件句柄添加到 Looper 中了,用来监听,一旦有数据到来,则回调 this (此处为 DisplayEventDispatcher) 中所复写 LooperCallback 对象的 handleEvent。

三 Vysnc回调流程

接上分析,当 Vysnc 信号由 SurfaceFlinger 中创建 HWC 触发,唤醒 DispSyncThread 线程,再到 EventThread 线程,然后再通过 BitTube 直接传递到目标进程所对应的目标线程,(这一部分内容,请参考 SurfaceFlinger 流程)执行 handleEvent 方法。

3.1 DisplayEventDispatcher.handleEvent

framework/base/libs/androidfw/DisplayEventDispatcher.cpp

int DisplayEventDispatcher::handleEvent(int, int events, void*) {
    if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) {
        ALOGE("Display event receiver pipe was closed or an error occurred.  "
                "events=0x%x", events);
        return 0; // remove the callback
    }

    if (!(events & Looper::EVENT_INPUT)) {
        ALOGW("Received spurious callback for unhandled poll event.  "
                "events=0x%x", events);
        return 1; // keep the callback
    }

    // Drain all pending events, keep the last vsync.
    nsecs_t vsyncTimestamp;
    PhysicalDisplayId vsyncDisplayId;
    uint32_t vsyncCount;
    //清除所有的pending事件,只保留最后一次vsync
    if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount)) {
        ALOGV("dispatcher %p ~ Vsync pulse: timestamp=%" PRId64 ", displayId=%"
                ANDROID_PHYSICAL_DISPLAY_ID_FORMAT ", count=%d",
                this, ns2ms(vsyncTimestamp), vsyncDisplayId, vsyncCount);
        mWaitingForVsync = false;
        //关键点:回调执行 dispatchVsync,用来分发 Vysnc
        dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount);
    }

    return 1; // keep the callback
}

3.2 NativeDisplayEventReceiver.dispatchVsync

android_view_DisplayEventReceiver.cpp

void NativeDisplayEventReceiver::dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId,
                                               uint32_t count) {
    JNIEnv* env = AndroidRuntime::getJNIEnv();

    ScopedLocalRef<jobject> receiverObj(env, jniGetReferent(env, mReceiverWeakGlobal));
    if (receiverObj.get()) {
        ALOGV("receiver %p ~ Invoking vsync handler.", this);
        //关键点:通过 JNI 调用 Java 层的 dispatchVsync 函数
        env->CallVoidMethod(receiverObj.get(),
                gDisplayEventReceiverClassInfo.dispatchVsync, timestamp, displayId, count);
        ALOGV("receiver %p ~ Returned from vsync handler.", this);
    }

    mMessageQueue->raiseAndClearException(env, "dispatchVsync");
}

DisplayEventReceiver.java

private void dispatchVsync(long timestampNanos, long physicalDisplayId, int frame) {
        onVsync(timestampNanos, physicalDisplayId, frame);
    }

最后回调到 Java 层 DisplayEventReceiver 的 onVsync,进而走到 FrameDisplayEventReceiver 的 onVsync。

3.3 onVsync

Choreographer.java

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
        public void onVsync(long timestampNanos, long physicalDisplayId, int frame) {
            long now = System.nanoTime();
            if (timestampNanos > now) {
                timestampNanos = now;
            }

            if (mHavePendingVsync) {
            } else {
                mHavePendingVsync = true;
            }

            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;
            // 在 run 方法中执行 doFrame
            doFrame(mTimestampNanos, mFrame);
        }
    }

可见 onVsync() 过程是通 过FrameHandler 向主线程 Looper 发送了一个自带 callback 的消息,此处 callback 为 FrameDisplayEventReceiver。 当主线程 Looper 执行到该消息时,则调用 FrameDisplayEventReceiver.run() 方法,从上面代码可以看出,在 run 方法中执行的是 doFrame 函数。

3.4 Choreographer.doFrame

Choreographer.java

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

            if (DEBUG_JANK && mDebugPrintNextFrameTimeDelta) {
                mDebugPrintNextFrameTimeDelta = false;
                Log.d(TAG, "Frame time delta: "
                    + ((frameTimeNanos - mLastFrameTimeNanos) * 0.000001f) + " ms");
            }

            long intendedFrameTimeNanos = frameTimeNanos;//原本计划的绘帧时间点
            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;
                if (DEBUG_JANK) {
                    Log.d(TAG, "Missed vsync by " + (jitterNanos * 0.000001f) + " ms "
                        + "which is more than the frame interval of "
                        + (mFrameIntervalNanos * 0.000001f) + " ms!  "
                        + "Skipping " + skippedFrames + " frames and setting frame "
                        + "time to " + (lastFrameOffset * 0.000001f) + " ms in the past.");
                }
                frameTimeNanos = startNanos - lastFrameOffset;//对齐帧的时间间隔
            }

            if (frameTimeNanos < mLastFrameTimeNanos) {
                if (DEBUG_JANK) {
                  Log.d(TAG, "Frame time appears to be going backwards.  May be due to a "
                      + "previously skipped frame.  Waiting for next vsync.");
                }
                scheduleVsyncLocked();
                return;
            }

            if (mFPSDivisor > 1) {
              long timeSinceVsync = frameTimeNanos - mLastFrameTimeNanos;
              if (timeSinceVsync < (mFrameIntervalNanos * mFPSDivisor) && timeSinceVsync > 0) {
                    scheduleVsyncLocked();
                    return;
                }
            }

            mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos);
            mFrameScheduled = false;
            mLastFrameTimeNanos = frameTimeNanos;
        }

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

        if (DEBUG_FRAMES) {
            final long endNanos = System.nanoTime();
            Log.d(TAG, "Frame " + frame + ": Finished, took "
                    + (endNanos - startNanos) * 0.000001f + " ms, latency "
                    + (startNanos - frameTimeNanos) * 0.000001f + " ms.");
        }
    }

此处 frameTimeNanos 是底层 Vsync 信号到达的时间戳。

  • 每调用一次 scheduleFrameLocked(),则 mFrameScheduled=true,能执行一次 doFrame() 操作,执行完 doFrame() 并设置 mFrameScheduled=false
  • 最终有如下4个回调类别
  1. INPUT:输入事件
  2. ANIMATION:动画
  3. TRAVERSAL:窗口刷新,执行 measure/layout/draw 操作
  4. COMMIT:遍历完成的提交操作,用来修正动画启动时间

3.5 Choreographer.doCallbacks

void doCallbacks(int callbackType, long frameTimeNanos) {
        CallbackRecord callbacks;
        synchronized (mLock) {
            final long now = System.nanoTime();
            // 从队列查找相应类型的CallbackRecord对象
            callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(
                    now / TimeUtils.NANOS_PER_MS);
            if (callbacks == null) {
                return;
            }
            mCallbacksRunning = true;
          
            if (callbackType == Choreographer.CALLBACK_COMMIT) {
                final long jitterNanos = now - frameTimeNanos;
                Trace.traceCounter(Trace.TRACE_TAG_VIEW, "jitterNanos", (int) jitterNanos);
                //当commit类型回调执行的时间点超过2帧,则更新mLastFrameTimeNanos
                if (jitterNanos >= 2 * mFrameIntervalNanos) {
                    final long lastFrameOffset = jitterNanos % mFrameIntervalNanos
                            + mFrameIntervalNanos;
                    if (DEBUG_JANK) {
                        Log.d(TAG, "Commit callback delayed by " + (jitterNanos * 0.000001f)
                                + " ms which is more than twice the frame interval of "
                                + (mFrameIntervalNanos * 0.000001f) + " ms!  "
                                + "Setting frame time to " + (lastFrameOffset * 0.000001f)
                                + " ms in the past.");
                        mDebugPrintNextFrameTimeDelta = true;
                    }
                    frameTimeNanos = now - lastFrameOffset;
                    mLastFrameTimeNanos = frameTimeNanos;
                }
            }
        }
        try {
            Trace.traceBegin(Trace.TRACE_TAG_VIEW, CALLBACK_TRACE_TITLES[callbackType]);
            for (CallbackRecord c = callbacks; c != null; c = c.next) {
                if (DEBUG_FRAMES) {
                    Log.d(TAG, "RunCallback: type=" + callbackType
                            + ", action=" + c.action + ", token=" + c.token
                            + ", latencyMillis=" + (SystemClock.uptimeMillis() - c.dueTime));
                }
                //关键点:执行 callback 的回调
                c.run(frameTimeNanos);
            }
        } finally {
            synchronized (mLock) {
                mCallbacksRunning = false;
                do {
                    final CallbackRecord next = callbacks.next;
                    //回收callbacks,加入对象池 mCallbackPool
                    recycleCallbackLocked(callbacks);
                    callbacks = next;
                } while (callbacks != null);
            }
            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
        }
    }

该方法主要功能:

  • 从队列头 mHead 查找 CallbackRecord 对象,当队列头部的 callbacks 对象为空或者执行时间还没到达,则直接返回
  • 开始执行相应回调的 run() 方法
  • 回收 callbacks,加入对象池 mCallbackPool,就是说 callback 一旦执行完成,则会被回收

3.6 CallbackRecord.run

private static final class CallbackRecord {
        public CallbackRecord next;
        public long dueTime;
        public Object action; // Runnable or FrameCallback
        public Object token;

        @UnsupportedAppUsage
        public void run(long frameTimeNanos) {
            if (token == FRAME_CALLBACK_TOKEN) {
                ((FrameCallback)action).doFrame(frameTimeNanos);
            } else {
                ((Runnable)action).run();
            }
        }
    }

这里的回调方法 run() 有两种执行情况:

  • 当 token 的数据类型为 FRAME_CALLBACK_TOKEN,则执行该对象的 doFrame() 方法
  • 当 token 为其他类型,则执行该对象的 run() 方法

那么需要的场景便是由 WMS 调用 scheduleAnimationLocked() 方法来设置 mFrameScheduled=true 来触发动画, 接下来说说动画控制的过程。

四 动画显示过程

调用栈:

WMS.scheduleAnimationLocked
  postFrameCallback
    postFrameCallbackDelayed
      postCallbackDelayedInternal
        scheduleFrameLocked

4.1 WMS.scheduleAnimationLocked

WindowManagerService.java

void scheduleAnimationLocked() {
        if (mAnimator != null) {
            mAnimator.scheduleAnimation();
        }
    }

这里的 mAnimator 指的是 WindowAnimator。

4.1.1 WindowAnimator.scheduleAnimation

void scheduleAnimation() {
        if (!mAnimationFrameCallbackScheduled) {
            mAnimationFrameCallbackScheduled = true;
            mChoreographer.postFrameCallback(mAnimationFrameCallback);
        }
    }

4.1.2 WindowAnimator的创建

private WindowManagerService(
    ......
    mAnimator = new WindowAnimator(this);
    ......
}

WindowAnimator(final WindowManagerService service) {
        mService = service;
        mContext = service.mContext;
        mPolicy = service.mPolicy;
        AnimationThread.getHandler().runWithScissors(
                () -> mChoreographer = Choreographer.getSfInstance(), 0 /* timeout */);

        mAnimationFrameCallback = frameTimeNs -> {
            synchronized (mService.mGlobalLock) {
                mAnimationFrameCallbackScheduled = false;
            }
            animate(frameTimeNs);
        };
}

mAnimationFrameCallback 的数据类型为 Choreographer.FrameCallback。从以上代码可以看出 Choreographer 构造在 AnimationThread 线程中。

4.2 postFrameCallback

Choreographer.java

public void postFrameCallback(FrameCallback callback) {
        postFrameCallbackDelayed(callback, 0);
}

public void postFrameCallbackDelayed(FrameCallback callback, long delayMillis) {
        if (callback == null) {
            throw new IllegalArgumentException("callback must not be null");
        }

        postCallbackDelayedInternal(CALLBACK_ANIMATION,
                callback, FRAME_CALLBACK_TOKEN, delayMillis);
}

4.3 postCallbackDelayedInternal

// callbackType为动画,action为mAnimationFrameCallback
// token为FRAME_CALLBACK_TOKEN,delayMillis=0
private void postCallbackDelayedInternal(int callbackType,
            Object action, Object token, long delayMillis) {
        if (DEBUG_FRAMES) {
            Log.d(TAG, "PostCallback: type=" + callbackType
                    + ", action=" + action + ", token=" + token
                    + ", delayMillis=" + delayMillis);
        }

        synchronized (mLock) {
            final long now = SystemClock.uptimeMillis();
            final long dueTime = now + delayMillis;
            //添加到mCallbackQueues队列
            mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);

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

因为 dueTime == now,所以调用 scheduleFrameLocked。

4.4 scheduleFrameLocked

private void scheduleFrameLocked(long now) {
        if (!mFrameScheduled) {
            mFrameScheduled = true;
            if (USE_VSYNC) {
                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);
                }
            } else {
                final long nextFrameTime = Math.max(
                        mLastFrameTimeNanos / TimeUtils.NANOS_PER_MS + sFrameDelay, now);
                if (DEBUG_FRAMES) {
                    Log.d(TAG, "Scheduling next frame in " + (nextFrameTime - now) + " ms.");
                }
                Message msg = mHandler.obtainMessage(MSG_DO_FRAME);
                msg.setAsynchronous(true);
                mHandler.sendMessageAtTime(msg, nextFrameTime);
            }
        }
}

private boolean isRunningOnLooperThreadLocked() {
        return Looper.myLooper() == mLooper;
}

这里的 Choreographer 运行在 AnimationThread 线程中,所以 isRunningOnLooperThreadLocked 为 false,则发送 MSG_DO_SCHEDULE_VSYNC,从之前的分析可知,最终调用到 doScheduleVsync。

4.5 doScheduleVsync

void doScheduleVsync() {
        synchronized (mLock) {
            if (mFrameScheduled) {
                scheduleVsyncLocked();
            }
        }
    }

4.6 scheduleVsyncLocked

private void scheduleVsyncLocked() {
        mDisplayEventReceiver.scheduleVsync();
    }

mDisplayEventReceiver 对象是在 Choreographer 的实例化过程所创建的。

4.7 DisplayEventReceiver.scheduleVsync

public void scheduleVsync() {
        if (mReceiverPtr == 0) {
            Log.w(TAG, "Attempted to schedule a vertical sync pulse but the display event "
                    + "receiver has already been disposed.");
        } else {
            nativeScheduleVsync(mReceiverPtr);
        }
    }

4.8 nativeScheduleVsync

static void nativeScheduleVsync(JNIEnv* env, jclass clazz, jlong receiverPtr) {
    sp<NativeDisplayEventReceiver> receiver =
            reinterpret_cast<NativeDisplayEventReceiver*>(receiverPtr);
    status_t status = receiver->scheduleVsync();
    if (status) {
        String8 message;
        message.appendFormat("Failed to schedule next vertical sync pulse.  status=%d", status);
        jniThrowRuntimeException(env, message.string());
    }
}

4.9 DisplayEventDispatcher.scheduleVsync

DisplayEventDispatcher.cpp

status_t DisplayEventDispatcher::scheduleVsync() {
    if (!mWaitingForVsync) {
        ALOGV("dispatcher %p ~ Scheduling vsync.", this);

        // Drain all pending events.
        nsecs_t vsyncTimestamp;
        PhysicalDisplayId vsyncDisplayId;
        uint32_t vsyncCount;
        if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount)) {
            ALOGE("dispatcher %p ~ last event processed while scheduling was for %" PRId64 "",
                    this, ns2ms(static_cast<nsecs_t>(vsyncTimestamp)));
        }
       //关键点:请求requestNextVsync
        status_t status = mReceiver.requestNextVsync();
        if (status) {
            ALOGW("Failed to request next vsync, status=%d", status);
            return status;
        }

        mWaitingForVsync = true;
    }
    return OK;
}

我们看到最终调用的是 mReceiver 的 requestNextVsync 方法,这个 mReceiver 是什么呢?我们来看 DisplayEventDispatcher.h 文件

DisplayEventDispatcher.h

#include  
#include 
#include 

namespace android {

class DisplayEventDispatcher : public LooperCallback {
public:
    explicit DisplayEventDispatcher(const sp<Looper>& looper,
            ISurfaceComposer::VsyncSource vsyncSource = ISurfaceComposer::eVsyncSourceApp,
            ISurfaceComposer::ConfigChanged configChanged = ISurfaceComposer::eConfigChangedSuppress);

    status_t initialize();
    void dispose();
    status_t scheduleVsync();

protected:
    virtual ~DisplayEventDispatcher() = default;

private:
    sp<Looper> mLooper;
    // 关键点:gui 路径下的 DisplayEventReceiver
    DisplayEventReceiver mReceiver;
    bool mWaitingForVsync;

    virtual void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count) = 0;
    virtual void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId,
                                 bool connected) = 0;
    virtual void dispatchConfigChanged(nsecs_t timestamp, PhysicalDisplayId displayId,
                                       int32_t configId) = 0;

    virtual int handleEvent(int receiveFd, int events, void* data);
    bool processPendingEvents(nsecs_t* outTimestamp, PhysicalDisplayId* outDisplayId,
                              uint32_t* outCount);
};
}

4.10 requestNextVsync

frameworks/native/libs/gui/DisplayEventReceiver.cpp

status_t DisplayEventReceiver::requestNextVsync() {
    if (mEventConnection != nullptr) {
        mEventConnection->requestNextVsync();
        return NO_ERROR;
    }
    return NO_INIT;
}

该方法的作用请求下一次 Vsync 信息处理。

五 总结

  • 尽量避免在执行动画渲染的前后在主线程放入耗时操作,否则会造成卡顿感,影响用户体验
  • 可通过 Choreographer.getInstance().postFrameCallback() 来监听帧率情况
  • 每调用一次 scheduleFrameLocked(),则 mFrameScheduled = true,可进入 doFrame() 方法体内部,执行完 doFrame() 并设置mFrameScheduled=false
  • doCallbacks 回调方法有4个类别:INPUT(输入事件),ANIMATION(动画),TRAVERSAL(窗口刷新),COMMIT(完成后的提交操作)

你可能感兴趣的:(Android,framework)