Android Choreographer机制
发布日期:2021-05-06 20:20:22 浏览次数:20 分类:技术文章

本文共 28314 字,大约阅读时间需要 94 分钟。

一 概述

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

我们知道 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
sThreadInstance = new ThreadLocal
() {
@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
(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 = android_os_MessageQueue_getMessageQueue(env, messageQueueObj); if (messageQueue == NULL) {
jniThrowRuntimeException(env, "MessageQueue is not initialized."); return 0; } sp
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
(receiver.get());}

2.4.3 创建NativeDisplayEventReceiver

NativeDisplayEventReceiver::NativeDisplayEventReceiver(JNIEnv* env,        jobject receiverWeak, const sp
& messageQueue, jint vsyncSource, jint configChanged) : DisplayEventDispatcher(messageQueue->getLooper(), static_cast
(vsyncSource), static_cast
(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
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=0private 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
receiver = reinterpret_cast
(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
(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, ISurfaceComposer::VsyncSource vsyncSource = ISurfaceComposer::eVsyncSourceApp, ISurfaceComposer::ConfigChanged configChanged = ISurfaceComposer::eConfigChangedSuppress); status_t initialize(); void dispose(); status_t scheduleVsync();protected: virtual ~DisplayEventDispatcher() = default;private: sp
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(完成后的提交操作)
上一篇:理解PendingIntent
下一篇:Android消息机制常见问题汇总

发表评论

最新留言

路过按个爪印,很不错,赞一个!
[***.219.124.196]2025年03月28日 10时10分00秒