Android底层渲染,Android 底层渲染 - 屏幕刷新机制源码分析

相关文章链接:

相关源码文件:

/frameworks/base/core/java/android/view/ViewRootImpl.java

/frameworks/base/core/java/android/view/Choreographer.java

/frameworks/base/core/java/android/view/DisplayEventReceiver.java

/frameworks/base/core/jni/android_view_DisplayEventReceiver.cpp

/frameworks/native/libs/gui/DisplayEventReceiver.cpp

/frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp

/frameworks/native/services/surfaceflinger/EventThread.cpp

/frameworks/native/libs/gui/BitTube.cpp

1. 梳理概述

在开始阅读文章前,希望大家能认真思考几个问题:

界面卡顿的原理是怎样的?

ViewRootImpl 与 SurfaceFlinger 是怎么通信的?

invalidate / requestLayout 会不会立马刷新屏幕?

SurfaceView / GLSurfaceView 的底层实现原理?

搞 Android 搞了几年,我们对 VSync 信号应该会有一些了解,但是未必真正能理解其具体原理。比如 VSync 信号是从哪里来的?发到哪里去?有什么作用?本文主要讲解发到哪里去,至于从哪里来的大家可以看看之前的内容。

2. 请求 VSync 信号

如果我们的界面需要发生变化,一般都会来到 ViewRootImpl 的 requestLayout 方法,有可能是手动触发的也有可能是被动触发的,在这个方法里面我们会主动去请求接收 VSync 信号,当下一次 VSync 信号的来的时候会主动回掉回来,然后才开始真正的绘制流程。

@Override

public void requestLayout() {

if (!mHandlingLayoutInLayoutRequest) {

checkThread();

mLayoutRequested = true;

scheduleTraversals();

}

}

void scheduleTraversals() {

if (!mTraversalScheduled) {

mTraversalScheduled = true;

// 插入一条消息屏障

mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();

// post 一个 Callback

mChoreographer.postCallback(Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);

}

}

private void postCallbackDelayedInternal(int callbackType, Object action, Object token, long delayMillis) {

synchronized (mLock) {

...

if (dueTime <= now) {

scheduleFrameLocked(now);

} else {

...

}

}

}

private void scheduleFrameLocked(long now) {

if (!mFrameScheduled) {

mFrameScheduled = true;

if (USE_VSYNC) {

// 是否在 Choreographer 的工作线程

if (isRunningOnLooperThreadLocked()) {

scheduleVsyncLocked();

} else {

Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);

msg.setAsynchronous(true);

mHandler.sendMessageAtFrontOfQueue(msg);

}

} else {

...

}

}

}

// 请求接收下一次 VSync 信号

private void scheduleVsyncLocked() {

mDisplayEventReceiver.scheduleVsync();

}

由上面的源码可以看出,每一次调用 requestLayout 方法,都会主动调用 scheduleVsync 方法来接收下一次的 VSync 信号。也就是说在下一次 VSync 信号来之前,就算连续调用 n 次的 requestLayout 方法,也并不会触发刷新绘制流程。

3. 接收 VSync 信号

应用 App 请求了要接收下一次的 VSync 信号,那么 SurfaceFlinger 服务怎么把 VSync 信号,发给我们的应用 App ?这个得从 DisplayEventReceiver 的初始化入手,涉及到跨进程通信也涉及到 Native 层源码。

public DisplayEventReceiver(Looper looper) {

...

// nativeInit

mReceiverPtr = nativeInit(new WeakReference(this), mMessageQueue);

}

static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak, jobject messageQueueObj) {

sp receiver = new NativeDisplayEventReceiver(env, receiverWeak, messageQueue);

// 初始化方法

status_t status = receiver->initialize();

receiver->incStrong(gDisplayEventReceiverClassInfo.clazz); // retain a reference for the object

return reinterpret_cast(receiver.get());

}

status_t NativeDisplayEventReceiver::initialize() {

// 接收端的 fd 添加到 Looper

int rc = mMessageQueue->getLooper()->addFd(mReceiver.getFd(), 0, Looper::EVENT_INPUT,this, NULL);

return OK;

}

// 跨进程创建一个 mEventConnection 对象

DisplayEventReceiver::DisplayEventReceiver() {

sp sf(ComposerService::getComposerService());

if (sf != NULL) {

mEventConnection = sf->createDisplayEventConnection();

if (mEventConnection != NULL) {

mDataChannel = mEventConnection->getDataChannel();

}

}

}

// 获取接收端的 fd

int DisplayEventReceiver::getFd() const {

if (mDataChannel == NULL)

return NO_INIT;

return mDataChannel->getFd();

}

// VSync 信号来会回调到这个方法

int NativeDisplayEventReceiver::handleEvent(int receiveFd, int events, void* data) {

// Drain all pending events, keep the last vsync.

nsecs_t vsyncTimestamp;

int32_t vsyncDisplayId;

uint32_t vsyncCount;

if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount)) {

mWaitingForVsync = false;

dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount);

}

return 1; // keep the callback

}

void NativeDisplayEventReceiver::dispatchVsync(nsecs_t timestamp, int32_t id, uint32_t count) {

JNIEnv* env = AndroidRuntime::getJNIEnv();

ScopedLocalRef receiverObj(env, jniGetReferent(env, mReceiverWeakGlobal));

if (receiverObj.get()) {

// 回掉到 Java 层的 dispatchVsync 方法

env->CallVoidMethod(receiverObj.get(),

gDisplayEventReceiverClassInfo.dispatchVsync, timestamp, id, count);

}

}

@Override

public void onVsync(long timestampNanos, int builtInDisplayId, int frame) {

// 发消息执行 doFrame 方法,真正开始刷新绘制流程

mTimestampNanos = timestampNanos;

mFrame = frame;

Message msg = Message.obtain(mHandler, this);

msg.setAsynchronous(true);

mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);

}

DisplayEventReceiver 在初始化时会创建与 SurfaceFlinger 的 Connection 连接,当应用 App 主动发起 requestNextVsync 后,SurfaceFlinger 会在下一个 VSync 信号来的时候,主动通知我们的应用 App ,回掉到 Java 层的 onVsync 方法,开始真正的刷新绘制流程。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值