Android Choreographer源码分析

     搞客户端开发,时间也有点了,但是每次想起来,总感觉自己掌握的东西零零散散,没有一点集在的感觉,应用层的懂,framework的也懂,框架啥的了解一点,分层的思想也有一些,JVM的原理啊,内存分配和管理啊,运行机制啊啥的也知道一点,每次下班或者没事了,就在考虑,自己应该有一个主攻方向,往这个方向集中发展一下,首选的几个目标应该是非常清楚的,我们要掌握android,那么关于android的View机制、动画原理这些都是必须要掌握的,所以呢,自己想在这几个方面花些时间,好好研究一下,这样才能使自己更具竞争力。

     好了,不管是要了解View机制,还是android动画,我们应该都需要有Choreographer的知识,明白系统刷新机制到底是怎么样的,这样才能对其他方面有更好的辅助。本章博客,我们就来学习一下Android中的Choreographer的运行机制。

     我们都知道,应用层的一个Activity对应一个根View(也就是一个DecorView)、一个WindowState、一个ViewRootImpl,每个对象都非常重要,都是在Activity添加过程中重量级的对象,DecorView是当前Activity的根View,它里面管理着当前界面的View树;WindowState对象是当前Activity窗口在系统侧WindowManagerService中代理对象;ViewRootImpl则肩负着View的标准三步曲的处理和事件分发,而View绘制也是由Choreographer指导的,Choreographer的英文意思就是编舞者、舞蹈指挥,看着非常形象。那我们就从Choreographer对象的构建开始说起吧,它的构建是在ViewRootImpl的构造方法中的,代码如下:

public ViewRootImpl(Context context, Display display) {
        mContext = context;
        mWindowSession = WindowManagerGlobal.getWindowSession();
        mDisplay = display;
        mBasePackageName = context.getBasePackageName();

        mDisplayAdjustments = display.getDisplayAdjustments();

        mThread = Thread.currentThread();
        mLocation = new WindowLeaked(null);
        mLocation.fillInStackTrace();
        mWidth = -1;
        mHeight = -1;
        mDirty = new Rect();
        mTempRect = new Rect();
        mVisRect = new Rect();
        mWinFrame = new Rect();
        mWindow = new W(this);
        mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
        mViewVisibility = View.GONE;
        mTransparentRegion = new Region();
        mPreviousTransparentRegion = new Region();
        // [+LEUI-9331]
        mPreBlurParams = new BlurParams();
        // [-LEUI-9331]
        mFirst = true; // true for the first time the view is added
        mAdded = false;
        mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this);
        mAccessibilityManager = AccessibilityManager.getInstance(context);
        mAccessibilityInteractionConnectionManager =
            new AccessibilityInteractionConnectionManager();
        mAccessibilityManager.addAccessibilityStateChangeListener(
                mAccessibilityInteractionConnectionManager);
        mHighContrastTextManager = new HighContrastTextManager();
        mAccessibilityManager.addHighTextContrastStateChangeListener(
                mHighContrastTextManager);
        mViewConfiguration = ViewConfiguration.get(context);
        mDensity = context.getResources().getDisplayMetrics().densityDpi;
        mNoncompatDensity = context.getResources().getDisplayMetrics().noncompatDensityDpi;
        mFallbackEventHandler = new PhoneFallbackEventHandler(context);
        mChoreographer = Choreographer.getInstance();
        mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
        loadSystemProperties();

        /**
         * M: increase instance count and check log property to determine
         * whether to enable/disable log system. @{
         */
        mIdent = sIdent++;
        checkViewRootImplLogProperty();
        if (LOCAL_LOGV) {
            enableLog(true, "a");
        }

        if (DEBUG_LIFECYCLE) {
            Log.v(TAG, "ViewRootImpl construct: context = " + context + ", mThread = " + mThread
                    + ", mChoreographer = " + mChoreographer + ", mTraversalRunnable = "
                    + mTraversalRunnable + ", this = " + this);
        }
    }

     从构造方法中可以看到Choreographer是单例模式的,也就是一个ViewRootImpl对象对应一个Choreographer,当界面需要重绘时,都会调用到ViewRootImp类的scheduleTraversals()方法,这里的实现也比较简单,代码如下:

    void scheduleTraversals() {
        if (!mTraversalScheduled) {
            mTraversalScheduled = true;
            mTraversalBarrier = mHandler.getLooper().postSyncBarrier();
            mChoreographer.postCallback(
                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
            scheduleConsumeBatchedInput();
        }
    }

     mTraversalScheduled表示是否已经发起重绘,每次scheduleTraversals()方法调用之后,就会将它置为true,然后在下次调用doTraversal()又先将它置为false,然后调用mChoreographer.postCallback()添加一个Runnable,请注意,第一个参数是Choreographer.CALLBACK_TRAVERSAL,在Choreographer当前,添加的类型一共有三种,分别是:CALLBACK_INPUT、CALLBACK_ANIMATION、CALLBACK_TRAVERSAL,分别表示事件回调、动画回调、绘制回调。postCallback()方法是转而调用postCallbackDelayed()方法的,最后一个参数delayMillis传的是0,表示当前的重绘不需要延时,我们跟进去看一下添加的postCallbackDelayed()方法的代码:

    /**
     * Posts a callback to run on the next frame after the specified delay.
     * 

* The callback runs once then is automatically removed. *

* * @param callbackType The callback type. * @param action The callback action to run during the next frame after the specified delay. * @param token The callback token, or null if none. * @param delayMillis The delay time in milliseconds. * * @see #removeCallback * @hide */ public void postCallbackDelayed(int callbackType, Runnable action, Object token, long delayMillis) { if (action == null) { throw new IllegalArgumentException("action must not be null"); } if (callbackType < 0 || callbackType > CALLBACK_LAST) { throw new IllegalArgumentException("callbackType is invalid"); } postCallbackDelayedInternal(callbackType, action, token, delayMillis); }
     首先判断参数action是否为空,action就是我们要回调的对象,回调对象都为空了,那我们还干啥呢?其实判断callbackType,在整个过程中,只定义了上面描述的三种类型的事件,如果传入的type值不符合,那就抛出一个IllegalArgumentException("callbackType is invalid")异常。参数正常了,继续调用postCallbackDelayedInternal()进一步处理。postCallbackDelayedInternal()方法的代码如下:

    private void postCallbackDelayedInternal(int callbackType,
            Object action, Object token, long delayMillis) {
        if (DEBUG) {
            Log.d(TAG, "PostCallback: type=" + callbackType
                    + ", action=" + action + ", token=" + token
                    + ", delayMillis=" + delayMillis);
        }

        synchronized (mLock) {
            final long now = SystemClock.uptimeMillis();
            final long dueTime = now + delayMillis;
            mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);

            if (dueTime <= now) {
                scheduleFrameLocked(now);
            } else {
                Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
                msg.arg1 = callbackType;
                msg.setAsynchronous(true);
                mHandler.sendMessageAtTime(msg, dueTime);
            }
        }
    }
     此处获取当前时间,然后加上要延迟的时间,作为当前Callback的时间点,以这个时间点作为标准,把Callback对象添加到mCallbackQueues[callbackType]队列当中,这块的逻辑和Looper、MessageQueue、Handler中添加Message的逻辑很相似,大家可以对比学习。然后判断dueTime <= now,这块的逻辑看了半天,我确实没看懂,dueTime会有比now小的情况吗,也就是传进来的delayMillis小于0,再往上讲,就是当前要添加的回调要在上一次添加的回调之前,这感觉不太可能吧?如果有弄懂的朋友,烦请解答一下。此处应该是执行else分支,往当前的队列中添加一个Message,那么通过Handler机制就会进行处理,此处的mHandler是一个FrameHandler对象,我们来看一下FrameHandler的代码:
    private final class FrameHandler extends Handler {
        public FrameHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_DO_FRAME:
                    doFrame(System.nanoTime(), 0);
                    break;
                case MSG_DO_SCHEDULE_VSYNC:
                    doScheduleVsync();
                    break;
                case MSG_DO_SCHEDULE_CALLBACK:
                    doScheduleCallback(msg.arg1);
                    break;
            }
        }
    }
     这里的message消息也比较简单,MSG_DO_FRAME指系统在没有使用Vsync机制的时候,使用异步消息来刷新屏幕,当然,大家一定要理解,此处的刷新其实只是刷新屏幕工作的很小一部分,只是回调ViewRootImpl方法中添加的Runnable对象,最终是调用根View的draw方法,让每个子View有把自己的图像元素填充到分配好的显存当中,而要完全显示,还有很多工作要作,最终是在SurfaceFlinger类中对所有窗口的View进行合成,然后渲染,最终post到FrameBuffer上,才能显示出来的;MSG_DO_SCHEDULE_VSYNC当然就是指系统使用Vsync来刷新了;MSG_DO_SCHEDULE_CALLBACK就是指添加Callback或者FrameCallback完成的消息了。好了,我们继续看MSG_DO_SCHEDULE_CALLBACK的消息处理,它是调用doScheduleCallback(msg.arg1)来进行处理的,msg.arg1是刚才添加消息时的类型。我们整个看一下handleMessage()方法的代码,发现非常简单,这也是一个非常好的习惯,我们平时的代码当中,也应该尽量这样实现,这样一眼就可以看出来这个方法所要作的事情,把具体的处理放到每个细节方法中去。我们来看一下doScheduleCallback()方法的实现:
    void doScheduleCallback(int callbackType) {
        synchronized (mLock) {
            if (!mFrameScheduled) {
                final long now = SystemClock.uptimeMillis();
                if (mCallbackQueues[callbackType].hasDueCallbacksLocked(now)) {
                    scheduleFrameLocked(now);
                }
            }
        }
    }
     mFrameScheduled和ViewRootImpl的scheduleTraversals()方法中的变量mTraversalScheduled作用是一样的,也是判断当前是否正在执行添加,然后调用(mCallbackQueues[callbackType].hasDueCallbacksLocked(now))判断是否已处理过Callback事务,该方法的判断也很简单,(mHead != null && mHead.dueTime <= now),如果当前队列头不为空,并且队列头元素的时间点小于当前的时间点,那就说明是之前添加的,则需要对它进行处理;相反,如果队列头为空或者添加的时间点大于当前的时间点,也就是要延迟处理,则不需要任何操作。条件符合的话,就调用scheduleFrameLocked(now)进一步处理,我们来看一下scheduleFrameLocked()方法的实现:
    private void scheduleFrameLocked(long now) {
        if (!mFrameScheduled) {
            mFrameScheduled = true;
            if (USE_VSYNC) {
                if (DEBUG) {
                    Log.d(TAG, "Scheduling next frame on vsync.");
                }

                // If running on the Looper thread, then schedule the vsync immediately,
                // otherwise post a message to schedule the vsync from the UI thread
                // as soon as possible.
                if (isRunningOnLooperThreadLocked()) {
                    scheduleVsyncLocked();
                } else {
                    Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
                    msg.setAsynchronous(true);
                    mHandler.sendMessageAtFrontOfQueue(msg);
                }
            } else {
                final long nextFrameTime = Math.max(
                        mLastFrameTimeNanos / NANOS_PER_MS + sFrameDelay, now);
                if (DEBUG) {
                    Log.d(TAG, "Scheduling next frame in " + (nextFrameTime - now) + " ms.");
                }
                Message msg = mHandler.obtainMessage(MSG_DO_FRAME);
                msg.setAsynchronous(true);
                mHandler.sendMessageAtTime(msg, nextFrameTime);
            }
        }
    }
     此片一开始就把mFrameScheduled赋值为true,表示事务开始执行了,那么上面doScheduleCallback()方法当中的代码此该就不会再执行了。接下来的逻辑以USE_VSYNC分开,意思也非常明了,就是系统是否使用Vsync刷新机制,它是通过获取系统属性得到的,private static final boolean USE_VSYNC =  SystemProperties.getBoolean("debug.choreographer.vsync", true)。如果使用了Vsync垂直同步机制,则一步判断当前线程是否具备消息循环,如果有消息循环,则立即请求下一次Vsync信号,如果不具有消息循环,则通过当前进程的主线程请求Vsync信号;如果没有使用Vsync机制,则使用异步消息延时执行屏幕刷新。是否具有消息循环是通过调用isRunningOnLooperThreadLocked()方法完成判断的,它的实现很简单,return Looper.myLooper() == mLooper。因为当Choreographer对象在创建的时候,参数looper就是调用Looper looper = Looper.myLooper()获取回来的,也就是说当前进程肯定是有消息循环的,所以此处的判断为true,其他两个分支:当前线程不具备消息循环和系统未使用Vsync同步机制的逻辑,我们就不分析了,大家有兴趣的话,可以自己跟踪一下。进入if分支,继续调用scheduleVsyncLocked()方法进行处理,它的实现非常简单,就是调用mDisplayEventReceiver.scheduleVsync()来请求下一次Vsync信号。
     看到这里,是不是感觉逻辑有点多了,开始乱了,转来转去的,系统到底要干啥?呵呵,我们暂停下来梳理一下,系统作了这么多事情最终的目的就是在下一次Vsync信号到来的时候,将Choreographer当中的三个队列中的事务执行起来,这些事务是应用层ViewRootImpl在scheduleTraversals()方法中添加进去的,在Choreographer当中,我们要先将外边传进来的Callback放入队列,然后就要去请求Vsync信号,因为Vsync信号是定时产生的,你不请求,它就不会理你,当然你收不到回调,也就不知道啥时候通知ViewRootImpl执行View的measure、layout、draw了,这样说一下,大家清楚我们要干什么了吗?我第一次看Choreographer类的代码时候,看了半天,也是乱了,所以这里大概理一下。
     好,我们搞清楚目的了,继续往前走,我们现在已经将Callback添加到队列中了,下一步要作的就是请求Vsync信号了。mDisplayEventReceiver是一个FrameDisplayEventReceiver对象,我们来看一下它的代码定义:
    private final class FrameDisplayEventReceiver extends DisplayEventReceiver
            implements Runnable {
        private boolean mHavePendingVsync;
        private long mTimestampNanos;
        private int mFrame;

        public FrameDisplayEventReceiver(Looper looper) {
            super(looper);
        }

        @Override
        public void onVsync(long timestampNanos, int builtInDisplayId, int frame) {
            // Ignore vsync from secondary display.
            // This can be problematic because the call to scheduleVsync() is a one-shot.
            // We need to ensure that we will still receive the vsync from the primary
            // display which is the one we really care about.  Ideally we should schedule
            // vsync for a particular display.
            // At this time Surface Flinger won't send us vsyncs for secondary displays
            // but that could change in the future so let's log a message to help us remember
            // that we need to fix this.
            if (builtInDisplayId != SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN) {
                Log.d(TAG, "Received vsync from secondary display, but we don't support "
                        + "this case yet.  Choreographer needs a way to explicitly request "
                        + "vsync for a specific display to ensure it doesn't lose track "
                        + "of its scheduled vsync.");
                scheduleVsync();
                return;
            }

            // Post the vsync event to the Handler.
            // The idea is to prevent incoming vsync events from completely starving
            // the message queue.  If there are no messages in the queue with timestamps
            // earlier than the frame time, then the vsync event will be processed immediately.
            // Otherwise, messages that predate the vsync event will be handled first.
            long now = System.nanoTime();
            if (timestampNanos > now) {
                Log.w(TAG, "Frame time is " + ((timestampNanos - now) * 0.000001f)
                        + " ms in the future!  Check that graphics HAL is generating vsync "
                        + "timestamps using the correct timebase.");
                timestampNanos = now;
            }

            if (mHavePendingVsync) {
                Log.w(TAG, "Already have a pending vsync event.  There should only be "
                        + "one at a time.");
            } else {
                mHavePendingVsync = true;
            }

            mTimestampNanos = timestampNanos;
            mFrame = frame;
            Message msg = Message.obtain(mHandler, this);
            msg.setAsynchronous(true);
            mHandler.sendMessageAtTime(msg, timestampNanos / NANOS_PER_MS);
        }

        @Override
        public void run() {
            mHavePendingVsync = false;
            doFrame(mTimestampNanos, mFrame);
        }
    }
     我们可以看到这里的mTimestampNanos时间定义都是纳秒级别的,因为Vsync信号是用来同步屏幕刷新频率的,所以对时间的要求非常高,才采用了纳秒级别的,如果大家对Vsync信号的产生机制不了解的话,可以看我前面的博客:Vsync垂直同步信号分发和SurfaceFlinger响应执行渲染流程分析(一),mDisplayEventReceiver类变量是在Choreographer的构造方法中赋值的,我们继续来看它的scheduleVsync()方法的实现,因为FrameDisplayEventReceiver类是继承DisplayEventReceiver的,而它没用对scheduleVsync()方法重写,所以是调用父类的:
    /**
     * Schedules a single vertical sync pulse to be delivered when the next
     * display frame begins.
     */
    public void scheduleVsync() {
        if (mReceiverPtr == 0) {
            Log.w(TAG, "Attempted to schedule a vertical sync pulse but the display event "
                    + "receiver has already been disposed.");
        } else {
            nativeScheduleVsync(mReceiverPtr);
        }
    }
     它的实现很简单,判断描述符mReceiverPtr是否合法,如果非法就打印日志,什么也不作了,合法的话,就继续调用native方法nativeScheduleVsync(mReceiverPtr)来请求Vsync信号。nativeScheduleVsync()方法实现在android_view_DisplayEventReceiver.cpp当中,是通过定义JNINativeMethod gMethods[]来定义方法调用指针的,因为此类的代码不多,这里就全部贴出来,方便大家查看:
/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#define LOG_TAG "DisplayEventReceiver"

//#define LOG_NDEBUG 0


#include "JNIHelp.h"

#include 
     
     
      
      
#include 
      
      
       
       
#include 
       
       
        
        
#include 
        
        
         
         
#include 
         
         
           #include "android_os_MessageQueue.h" namespace android { // Number of events to read at a time from the DisplayEventReceiver pipe. // The value should be large enough that we can quickly drain the pipe // using just a few large reads. static const size_t EVENT_BUFFER_SIZE = 100; static struct { jclass clazz; jmethodID dispatchVsync; jmethodID dispatchHotplug; } gDisplayEventReceiverClassInfo; class NativeDisplayEventReceiver : public LooperCallback { public: NativeDisplayEventReceiver(JNIEnv* env, jobject receiverObj, const sp 
          
            & messageQueue); status_t initialize(); void dispose(); status_t scheduleVsync(); protected: virtual ~NativeDisplayEventReceiver(); private: jobject mReceiverObjGlobal; sp 
           
             mMessageQueue; DisplayEventReceiver mReceiver; bool mWaitingForVsync; virtual int handleEvent(int receiveFd, int events, void* data); bool processPendingEvents(nsecs_t* outTimestamp, int32_t* id, uint32_t* outCount); void dispatchVsync(nsecs_t timestamp, int32_t id, uint32_t count); void dispatchHotplug(nsecs_t timestamp, int32_t id, bool connected); }; NativeDisplayEventReceiver::NativeDisplayEventReceiver(JNIEnv* env, jobject receiverObj, const sp 
            
              & messageQueue) : mReceiverObjGlobal(env->NewGlobalRef(receiverObj)), mMessageQueue(messageQueue), mWaitingForVsync(false) { ALOGV("receiver %p ~ Initializing input event receiver.", this); } NativeDisplayEventReceiver::~NativeDisplayEventReceiver() { JNIEnv* env = AndroidRuntime::getJNIEnv(); env->DeleteGlobalRef(mReceiverObjGlobal); } status_t NativeDisplayEventReceiver::initialize() { status_t result = mReceiver.initCheck(); if (result) { ALOGW("Failed to initialize display event receiver, status=%d", result); return result; } int rc = mMessageQueue->getLooper()->addFd(mReceiver.getFd(), 0, Looper::EVENT_INPUT, this, NULL); if (rc < 0) { return UNKNOWN_ERROR; } return OK; } void NativeDisplayEventReceiver::dispose() { ALOGV("receiver %p ~ Disposing display event receiver.", this); if (!mReceiver.initCheck()) { mMessageQueue->getLooper()->removeFd(mReceiver.getFd()); } } status_t NativeDisplayEventReceiver::scheduleVsync() { if (!mWaitingForVsync) { ALOGV("receiver %p ~ Scheduling vsync.", this); // Drain all pending events. nsecs_t vsyncTimestamp; int32_t vsyncDisplayId; uint32_t vsyncCount; processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount); status_t status = mReceiver.requestNextVsync(); if (status) { ALOGW("Failed to request next vsync, status=%d", status); return status; } mWaitingForVsync = true; } return OK; } int NativeDisplayEventReceiver::handleEvent(int receiveFd, int events, void* data) { if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) { ALOGE("Display event receiver pipe was closed or an error occurred. " "events=0x%x", events); return 0; // remove the callback } if (!(events & Looper::EVENT_INPUT)) { ALOGW("Received spurious callback for unhandled poll event. " "events=0x%x", events); return 1; // keep the callback } // Drain all pending events, keep the last vsync. nsecs_t vsyncTimestamp; int32_t vsyncDisplayId; uint32_t vsyncCount; if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount)) { ALOGV("receiver %p ~ Vsync pulse: timestamp=%lld, id=%d, count=%d", this, vsyncTimestamp, vsyncDisplayId, vsyncCount); mWaitingForVsync = false; dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount); } return 1; // keep the callback } bool NativeDisplayEventReceiver::processPendingEvents( nsecs_t* outTimestamp, int32_t* outId, uint32_t* outCount) { bool gotVsync = false; DisplayEventReceiver::Event buf[EVENT_BUFFER_SIZE]; ssize_t n; while ((n = mReceiver.getEvents(buf, EVENT_BUFFER_SIZE)) > 0) { ALOGV("receiver %p ~ Read %d events.", this, int(n)); for (ssize_t i = 0; i < n; i++) { const DisplayEventReceiver::Event& ev = buf[i]; switch (ev.header.type) { case DisplayEventReceiver::DISPLAY_EVENT_VSYNC: // Later vsync events will just overwrite the info from earlier // ones. That's fine, we only care about the most recent. gotVsync = true; *outTimestamp = ev.header.timestamp; *outId = ev.header.id; *outCount = ev.vsync.count; break; case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG: dispatchHotplug(ev.header.timestamp, ev.header.id, ev.hotplug.connected); break; default: ALOGW("receiver %p ~ ignoring unknown event type %#x", this, ev.header.type); break; } } } if (n < 0) { ALOGW("Failed to get events from display event receiver, status=%d", status_t(n)); } return gotVsync; } void NativeDisplayEventReceiver::dispatchVsync(nsecs_t timestamp, int32_t id, uint32_t count) { JNIEnv* env = AndroidRuntime::getJNIEnv(); ALOGV("receiver %p ~ Invoking vsync handler.", this); env->CallVoidMethod(mReceiverObjGlobal, gDisplayEventReceiverClassInfo.dispatchVsync, timestamp, id, count); ALOGV("receiver %p ~ Returned from vsync handler.", this); mMessageQueue->raiseAndClearException(env, "dispatchVsync"); } void NativeDisplayEventReceiver::dispatchHotplug(nsecs_t timestamp, int32_t id, bool connected) { JNIEnv* env = AndroidRuntime::getJNIEnv(); ALOGV("receiver %p ~ Invoking hotplug handler.", this); env->CallVoidMethod(mReceiverObjGlobal, gDisplayEventReceiverClassInfo.dispatchHotplug, timestamp, id, connected); ALOGV("receiver %p ~ Returned from hotplug handler.", this); mMessageQueue->raiseAndClearException(env, "dispatchHotplug"); } static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverObj, jobject messageQueueObj) { sp 
             
               messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj); if (messageQueue == NULL) { jniThrowRuntimeException(env, "MessageQueue is not initialized."); return 0; } sp 
              
                receiver = new NativeDisplayEventReceiver(env, receiverObj, messageQueue); status_t status = receiver->initialize(); if (status) { String8 message; message.appendFormat("Failed to initialize display event receiver. status=%d", status); jniThrowRuntimeException(env, message.string()); return 0; } receiver->incStrong(gDisplayEventReceiverClassInfo.clazz); // retain a reference for the object return reinterpret_cast 
               
                 (receiver.get()); } static void nativeDispose(JNIEnv* env, jclass clazz, jlong receiverPtr) { sp 
                
                  receiver = reinterpret_cast 
                 
                   (receiverPtr); receiver->dispose(); receiver->decStrong(gDisplayEventReceiverClassInfo.clazz); // drop reference held by the object } static void nativeScheduleVsync(JNIEnv* env, jclass clazz, jlong receiverPtr) { sp 
                  
                    receiver = reinterpret_cast 
                   
                     (receiverPtr); status_t status = receiver->scheduleVsync(); if (status) { String8 message; message.appendFormat("Failed to schedule next vertical sync pulse. status=%d", status); jniThrowRuntimeException(env, message.string()); } } static JNINativeMethod gMethods[] = { /* name, signature, funcPtr */ { "nativeInit", "(Landroid/view/DisplayEventReceiver;Landroid/os/MessageQueue;)J", (void*)nativeInit }, { "nativeDispose", "(J)V", (void*)nativeDispose }, { "nativeScheduleVsync", "(J)V", (void*)nativeScheduleVsync } }; #define FIND_CLASS(var, className) \ var = env->FindClass(className); \ LOG_FATAL_IF(! var, "Unable to find class " className); \ var = jclass(env->NewGlobalRef(var)); #define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \ var = env->GetMethodID(clazz, methodName, methodDescriptor); \ LOG_FATAL_IF(! var, "Unable to find method " methodName); int register_android_view_DisplayEventReceiver(JNIEnv* env) { int res = jniRegisterNativeMethods(env, "android/view/DisplayEventReceiver", gMethods, NELEM(gMethods)); LOG_FATAL_IF(res < 0, "Unable to register native methods."); FIND_CLASS(gDisplayEventReceiverClassInfo.clazz, "android/view/DisplayEventReceiver"); GET_METHOD_ID(gDisplayEventReceiverClassInfo.dispatchVsync, gDisplayEventReceiverClassInfo.clazz, "dispatchVsync", "(JII)V"); GET_METHOD_ID(gDisplayEventReceiverClassInfo.dispatchHotplug, gDisplayEventReceiverClassInfo.clazz, "dispatchHotplug", "(JIZ)V"); return 0; } } // namespace android 
                    
                   
                  
                 
                
               
              
             
            
           
         
        
        
       
       
      
      
     
     
     我们来看一下nativeScheduleVsync方法的定义,{ "nativeScheduleVsync", "(J)V", (void*)nativeScheduleVsync },这里需要说明一下,java方法和JNI方法存在着对应关系,"(J)V"括号里边的表示该方法的入参,括号外边的表示返回值J表示long,而返回值V表示Void,关于这个,大家可以看我之前的博客:JNI字段描述符“([Ljava/lang/String;)V”,也是转载别人的,呵呵。好了,我们继续看这个方法的实现,它将java层传进来的描述符强制转换为NativeDisplayEventReceiver对象,这样的处理在JNI当中是非常多见的,大家要熟悉。然后调用它的scheduleVsync()方法,最后根据返回值判断当前请求Vsync信号是否成功,如果status非0,则抛出RuntimeException异常。很明显,我们从这都可以猜出,正常情况下,返回的status应该为0了。
     我们继续来看NativeDisplayEventReceiver::scheduleVsync()方法的处理逻辑。首先检查mWaitingForVsync,如果当前正在请求Vsync信号,则就不需要重复请求了,只有在当前未请求的时候,才需要发出新的请求,然后调用processPendingEvents()将当前队列中还存在receiver处理掉,因此方法与我们的流程不相关,这里就不展开了,大致是使用pipe机制将mReceiver中还存在的receiver一一读出,大家如果了解Linux机制的话,就知道pipe机制对应了两个管道,管道中的数据被读出之后,也就相应的从管道中移除了,所以不需要两端对数据做任何移除的处理,每一个receiver处理完成后,就设置一下gotVsync = true,
*outTimestamp = ev.header.timestamp,*outId = ev.header.id,*outCount = ev.vsync.count,gotVsync的意思就是当前的receiver已经收到Vsync信号通知了。好了,我们回到主流程,scheduleVsync()方法当中处理完队列中的receiver后,就开始调用mReceiver.requestNextVsync()请求新的Vsync信号了,mReceiver是一个DisplayEventReceiver对象,我们来看一下requestNextVsync()方法的实现,因这个类的代码也很少,这里就直接全部贴出来了:
/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include 
     
     
      
      

#include 
      
      
       
       

#include 
       
       
        
        
#include 
        
        
         
         
#include 
         
         
           #include 
          
            #include 
           
             // --------------------------------------------------------------------------- namespace android { // --------------------------------------------------------------------------- DisplayEventReceiver::DisplayEventReceiver() { sp 
            
              sf(ComposerService::getComposerService()); if (sf != NULL) { mEventConnection = sf->createDisplayEventConnection(); if (mEventConnection != NULL) { mDataChannel = mEventConnection->getDataChannel(); } } } DisplayEventReceiver::~DisplayEventReceiver() { } status_t DisplayEventReceiver::initCheck() const { if (mDataChannel != NULL) return NO_ERROR; return NO_INIT; } int DisplayEventReceiver::getFd() const { if (mDataChannel == NULL) return NO_INIT; return mDataChannel->getFd(); } status_t DisplayEventReceiver::setVsyncRate(uint32_t count) { if (int32_t(count) < 0) return BAD_VALUE; if (mEventConnection != NULL) { mEventConnection->setVsyncRate(count); return NO_ERROR; } return NO_INIT; } status_t DisplayEventReceiver::requestNextVsync() { if (mEventConnection != NULL) { mEventConnection->requestNextVsync(); return NO_ERROR; } return NO_INIT; } ssize_t DisplayEventReceiver::getEvents(DisplayEventReceiver::Event* events, size_t count) { return DisplayEventReceiver::getEvents(mDataChannel, events, count); } ssize_t DisplayEventReceiver::getEvents(const sp 
             
               & dataChannel, Event* events, size_t count) { return BitTube::recvObjects(dataChannel, events, count); } ssize_t DisplayEventReceiver::sendEvents(const sp 
              
                & dataChannel, Event const* events, size_t count) { return BitTube::sendObjects(dataChannel, events, count); } // --------------------------------------------------------------------------- }; // namespace android 
               
              
             
            
           
         
        
        
       
       
      
      
     
     
     requestNextVsync()方法中直接调用mEventConnection->requestNextVsync()来请求Vsync信号,mEventConnection对象是在DisplayEventReceiver类的构造函数中创建的,mEventConnection = sf->createDisplayEventConnection(),sf就是SurfaceFlinger对象,SurfaceFlinger类的createDisplayEventConnection()实现也非常简单,就是调用mEventThread->createEventConnection(),这又回到我们之前的博客了,大家可以去看一下。
     EventThread一直在无限循环threadLoop()中请求Vsync信号的,当收到一个Vsync信号后,会调用status_t err = conn->postEvent(event)来进行分发,conn也就是上面的EventThread::Connection对象了,最后经过处理,回调到NativeDisplayEventReceiver::handleEvent(int receiveFd, int events, void* data)方法当中,这里同样processPendingEvents()处理完队列中的回调后,就调用dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount)开始分发了,在NativeDisplayEventReceiver::dispatchVsync()这个方法中是通过当前的native层的执行环境env回调到java层的,env->CallVoidMethod(mReceiverObjGlobal,
gDisplayEventReceiverClassInfo.dispatchVsync, timestamp, id, count),再往下就回调到java层中DisplayEventReceiver类的dispatchVsync()方法中了。它里边的实现就是调用onVsync(),而FrameDisplayEventReceiver复写了onVsync()方法,所以就执行到Choreographer.FrameDisplayEventReceiver中的onVsync()方法了。
     转了好大一圈,我们终于又从native层回来了。好,我们继续java层往下分析,Vsync信号拿回来了,大家应该也知道,我们的目的快达到了!!
     onVsync()方法中以this为对象,向mHandler中添加了一个消息,消息处理的时候,就会调用它的run()方法了。run方法中直接调用doFrame()来进行处理。我们来看一下它的实现:
    void doFrame(long frameTimeNanos, int frame) {
        final long startNanos;
        synchronized (mLock) {
            if (!mFrameScheduled) {
                return; // no work to do
            }

            startNanos = System.nanoTime();
            final long jitterNanos = startNanos - frameTimeNanos;
            if (jitterNanos >= mFrameIntervalNanos) {
                final long skippedFrames = jitterNanos / mFrameIntervalNanos;
                if (skippedFrames >= SKIPPED_FRAME_WARNING_LIMIT) {
                    Log.i(TAG, "Skipped " + skippedFrames + " frames!  "
                            + "The application may be doing too much work on its main thread.");
                }
                final long lastFrameOffset = jitterNanos % mFrameIntervalNanos;
                if (DEBUG) {
                    Log.d(TAG, "Missed vsync by " + (jitterNanos * 0.000001f) + " ms "
                            + "which is more than the frame interval of "
                            + (mFrameIntervalNanos * 0.000001f) + " ms!  "
                            + "Skipping " + skippedFrames + " frames and setting frame "
                            + "time to " + (lastFrameOffset * 0.000001f) + " ms in the past.");
                }
                frameTimeNanos = startNanos - lastFrameOffset;
            }

            if (frameTimeNanos < mLastFrameTimeNanos) {
                if (DEBUG) {
                    Log.d(TAG, "Frame time appears to be going backwards.  May be due to a "
                            + "previously skipped frame.  Waiting for next vsync.");
                }
                scheduleVsyncLocked();
                return;
            }

            mFrameScheduled = false;
            mLastFrameTimeNanos = frameTimeNanos;
        }

        doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);
        doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
        doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);

        if (DEBUG) {
            final long endNanos = System.nanoTime();
            Log.d(TAG, "Frame " + frame + ": Finished, took "
                    + (endNanos - startNanos) * 0.000001f + " ms, latency "
                    + (startNanos - frameTimeNanos) * 0.000001f + " ms.");
        }
    }
     如果(frameTimeNanos < mLastFrameTimeNanos)满足,则说明我们已经错过了本次的Vsync信号了,那么这种情况下,就什么也不用处理,重新获取下一次信号了。如果没有错过的话,那就进一步三次调用doCallbacks()分别对应三种事件类型来分发了。三种事件的顺序也是定义的顺序:CALLBACK_INPUT、CALLBACK_ANIMATION、CALLBACK_TRAVERSAL,这也是他们的处理优先级,输入事件放在第一,也是为了能尽快响应用户的操作,但是即使这样,Android的流畅性还是不如IOS,当然,这个原因就是其他方面的了,我们这里就不探讨了。我们来看一下doCallbacks()方法的实现:
    void doCallbacks(int callbackType, long frameTimeNanos) {
        CallbackRecord callbacks;
        synchronized (mLock) {
            // We use "now" to determine when callbacks become due because it's possible
            // for earlier processing phases in a frame to post callbacks that should run
            // in a following phase, such as an input event that causes an animation to start.
            final long now = SystemClock.uptimeMillis();
            callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(now);
            if (callbacks == null) {
                return;
            }
            mCallbacksRunning = true;
        }
        try {
            for (CallbackRecord c = callbacks; c != null; c = c.next) {
                if (DEBUG) {
                    Log.d(TAG, "RunCallback: type=" + callbackType
                            + ", action=" + c.action + ", token=" + c.token
                            + ", latencyMillis=" + (SystemClock.uptimeMillis() - c.dueTime));
                }
                c.run(frameTimeNanos);
            }
        } finally {
            synchronized (mLock) {
                mCallbacksRunning = false;
                do {
                    final CallbackRecord next = callbacks.next;
                    recycleCallbackLocked(callbacks);
                    callbacks = next;
                } while (callbacks != null);
            }
        }
    }
     这里就是将每种类型的事件队列中的元素取出来,通过for循环一一调用他们的run()方法了,调用完成后,将队列中的Callback回收掉。而这里的CallbackRecord对象就是我们在ViewRootImpl类当中添加的InvalidateOnAnimationRunnable、mConsumedBatchedInputRunnable、mTraversalRunnable这三类对象了,那么回到View的流程中,收到Vsync信号后,就会回调mTraversalRunnable的run()方法,再次发起一次measure、layout、draw流程,那么也就和Vsync信号对接上了。
     好了,到这里呢,我们整个流程也就分析完了,希望对大家有所帮助,谢谢大家!
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

红-旺永福

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值