Android-Choreographer工作原理,2021大厂Android面试经验

// mTraversalRunnable 是一个 Runnable 实例
final class TraversalRunnable implements Runnable {
@Override
public void run() {
doTraversal();
}
}

void doTraversal() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
// 移除同步屏障
mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
// 真正执行View的measure,layout,draw流程
performTraversals();
}
}

首先使用 mTraversalScheduled 字段保证同时间多次更改只会刷新一次,然后为当前线程的 MessageQueue 添加同步屏障来屏蔽同步消息,保证 VSync 信号到来后立即执行绘制,而不是要等前面的同步消息。调用 mChoreographer.postCallback() 方法发送了一个会在下一帧执行的回调,即在下一个 VSync 信号到来时会执行TraversalRunnable–>doTraversal()–>performTraversals()–>绘制流程。同步屏障可以参考 Android消息机制。

Choreographer实例化

首先看一下 Choreographer 的实例化过程,它在 ViewRootImpl 构造方法中实例化,ViewRootImpl 的实例化时机可以参考 Android-Window机制原理。

// ViewRootImpl在WindowManager.addView时创建
public ViewRootImpl(Context context, Display display) {
// ...
mChoreographer = Choreographer.getInstance();
// ...
}

public final class Choreographer {
private static volatile Choreographer mMainInstance;

private static final ThreadLocal sThreadInstance = new ThreadLocal() {
@Override
protected Choreographer initialValue() {
Looper looper = Looper.myLooper();
// VSYNC_SOURCE_APP = 0; -- APP
// VSYNC_SOURCE_SURFACE_FLINGER = 1; -- SurfaceFlinger
Choreographer choreographer = new Choreographer(looper, VSYNC_SOURCE_APP);
// ...
return choreographer;
}
};

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


可知 Choreographer 和 Looper 一样都是线程单例的,由 ThreadLocal 实现,参考ThreadLocal原理。

public final class Choreographer {
// 4.1以上默认是true
// Enable/disable vsync for animations and drawing.
private static final boolean USE_VSYNC = SystemProperties.getBoolean("debug.choreographer.vsync", true);

// VSync事件接收器
private final FrameDisplayEventReceiver mDisplayEventReceiver;

private Choreographer(Looper looper, int vsyncSource) {
mLooper = looper;
mDisplayEventReceiver = USE_VSYNC ? new FrameDisplayEventReceiver(looper, vsyncSource) : null;
// ...
}
}


在 Choreographer 实例化时创建了一个 FrameDisplayEventReceiver 对象,它用来注册 Vsync 信号。

# Vsync信号注册

# DisplayEventReceiver

mDisplayEventReceiver 是 FrameDisplayEventReceiver 类型的实例,在Choreographer构造方法中实例化,其父类为 DisplayEventReceiver。

public abstract class DisplayEventReceiver {
public static final int VSYNC_SOURCE_APP = 0;
private long mReceiverPtr;

public DisplayEventReceiver(Looper looper, int vsyncSource) {
mMessageQueue = looper.getQueue();
// 注册VSYNC信号监听者
mReceiverPtr = nativeInit(new WeakReference(this), mMessageQueue, vsyncSource);
}

private static native long nativeInit(WeakReference receiver, MessageQueue messageQueue, int vsyncSource);
}


# nativeInit

nativeInit是一个native方法,其实现在frameworks/base/core/jni/android_view_DisplayEventReceiver.cpp中:

static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,
jobject messageQueueObj, jint vsyncSource) {
sp messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
sp receiver = new NativeDisplayEventReceiver(env, receiverWeak, messageQueue, vsyncSource);
status_t status = receiver->initialize();
receiver->incStrong(gDisplayEventReceiverClassInfo.clazz); // retain a reference for the object
return reinterpret_cast(receiver.get());
}


NativeDisplayEventReceiver 继承自 DisplayEventDispatcher:

DisplayEventReceiver::DisplayEventReceiver(ISurfaceComposer::VsyncSource vsyncSource) {
sp sf(ComposerService::getComposerService());
if (sf != NULL) {
mEventConnection = sf->createDisplayEventConnection(vsyncSource);
if (mEventConnection != NULL) {
mDataChannel = std::make_unique();
mEventConnection->stealReceiveChannel(mDataChannel.get());
}
}
}

sp SurfaceFlinger::createDisplayEventConnection(
ISurfaceComposer::VsyncSource vsyncSource) {
if (vsyncSource == eVsyncSourceSurfaceFlinger) {
return mSFEventThread->createEventConnection();
} else {
// vsyncSource 是 APP
return mEventThread->createEventConnection();
}
}


从 SurfaceFlinger 启动与工作流程 可以知道 EventThread.createEventConnection 创建了一个对 Vsync 信号感兴趣的连接,具体逻辑可以阅读这篇文章。initialize 方法如下:

// frameworks/base/libs/androidfw/DisplayEventDispatcher.cpp
status_t DisplayEventDispatcher::initialize() {
// DisplayEventReceiver mReceiver;
status_t result = mReceiver.initCheck();
int rc = mLooper->addFd(mReceiver.getFd(), 0, Looper::EVENT_INPUT, this, NULL);
if (rc < 0) {
return UNKNOWN_ERROR;
}
return OK;
}

mReceiver 是 DisplayEventReceiver 类型实例,位于frameworks/native/libs/gui/DisplayEventReceiver.cpp。mLooper->addFd(mReceiver.getFd(), 0, Looper::EVENT_INPUT, this, NULL) 用来监听 mReceiver 所获取的文件句柄,当**有存在对 Vsync 信号感兴趣的连接**且**接收到了 Vsync 信号**时,会发送数据到 mReceiver, 然后回调到 DisplayEventDispatcher 中的 handleEvent 方法,具体源码参考 SurfaceFlinger 启动与工作流程 中 addFd 的解析。

# 请求Vsync信号

上面已经注册了一个对 Vsync 信号感兴趣的连接,在 Vsync 信号到来后,会回调到 DisplayEventDispatcher.handleEvent 方法。于是接下来我们需要请求 Vsync 信号。看一下上面调用的代码:mChoreographer.postCallback(Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null),它的调用链是: Choreographer.postCallback -> Choreographer.postCallbackDelayedInternal -> Choreographer.scheduleFrameLocked -> Choreographer.scheduleVsyncLocked 方法,节省篇幅,具体代码不贴出了:

private void postCallbackDelayedInternal(int callbackType, Object action, Object token, long delayMillis) {
synchronized (mLock) {
final long now = SystemClock.uptimeMillis();
final long dueTime = now + delayMillis;
// 对应类型的 CallbackQueue 添加 Callback
mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
// ...
}
}

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

// DisplayEventReceiver
public void scheduleVsync() {
if (mReceiverPtr == 0) {
// ...
} else {
nativeScheduleVsync(mReceiverPtr);
}
}


接着就到了 native 层代码:

// frameworks/base/core/jni/android_view_DisplayEventReceiver.cpp
static void nativeScheduleVsync(JNIEnv* env, jclass clazz, jlong receiverPtr) {
sp receiver = reinterpret_cast
上一篇:ffmpeg视频抽取帧


下一篇:最新Android面试题整理,深夜思考