美文网首页Android知识梳理
Android 底层渲染 - 屏幕刷新机制源码分析

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

作者: 红橙Darren | 来源:发表于2020-03-18 21:30 被阅读0次

    相关文章链接:

    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<DisplayEventReceiver>(this), mMessageQueue);
        }
    
        static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak, jobject messageQueueObj) {
          sp<NativeDisplayEventReceiver> receiver = new NativeDisplayEventReceiver(env, receiverWeak, messageQueue);
          // 初始化方法
          status_t status = receiver->initialize();
          receiver->incStrong(gDisplayEventReceiverClassInfo.clazz); // retain a reference for the object
          return reinterpret_cast<jlong>(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<ISurfaceComposer> 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<jobject> 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 底层渲染 - 屏幕刷新机制源码分析

        本文链接:https://www.haomeiwen.com/subject/otucyhtx.html