Android(安卓)底层渲染 - 屏幕刷新机制源码分析
相关文章链接:
1. Android Framework - 学习启动篇
2. 源码阅读分析 - Window底层原理与系统架构
相关源码文件:
/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 方法,开始真正的刷新绘制流程。
视频地址:https://pan.baidu.com/s/1tQ7omRNg8BgldnkjdlBPlw
视频密码:6hlc
更多相关文章
- android中GridView关于间距的属性值介绍
- Android(安卓)studio 连接数据库小经历遇到的问题以及解决方法(ja
- Android(安卓)属性动画简介
- 从零开始学习android
- 详解 Android(安卓)的 Activity 组件
- 详解 Android(安卓)的 Activity 组件
- Android中通过Intent 调用图片、视频、音频、录音、拍照
- android 关于tts的一些参数
- android中SharedPreferences和PreferenceActivity的存取数据