ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

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

2021-12-28 12:30:59  阅读:150  来源: 互联网

标签:Choreographer vsyncSource private 2021 Vsync DisplayEventReceiver Android public


// 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

标签:Choreographer,vsyncSource,private,2021,Vsync,DisplayEventReceiver,Android,public
来源: https://blog.csdn.net/m0_65145219/article/details/122190369

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有