1. 程式人生 > >Android訊息機制Looper與VSync的傳播

Android訊息機制Looper與VSync的傳播

#1 主要內容

本文主要簡單記錄在native層Looper訊息機制的相關內容,主要著手於下面幾個問題:
(1)訊息機制的原理;
(2)VSync是如何藉助訊息機制進行傳播的;

2 Android訊息機制

2.1 應用程序的建立

說起Android的訊息機制,先大致的理一下Android應用的執行機制,Android上層是基於訊息機制的,首先考慮一個問題,描述如下:Android應用作為執行在Linux平臺上的使用者程序,是如何保持一致處於執行狀態的?也就是如何做到主執行緒不結束,程序一直存在的?
要想搞清楚這個問題,首先得搞清楚Android應用程序是如何建立的,比如我們點選桌面上的icon,應用程序啟動了,然後介面出現了,只要不退出,介面一直存在,這整個的過程是怎麼樣的呢?下面分幾個步驟來說明這個問題:
(1)桌面Launcher應用也是一個Android應用,點選圖示啟動程序;
(2)ActivityManagerService接收到Activity的啟動請求,發現需要啟動的Activity所在的程序當前尚未執行,首先需要啟動程序;
(3)程序啟動後,Activity隨之被啟動,進入主執行緒的訊息迴圈,保持“不死狀態”;
本文主要討論訊息機制,為保持主題清晰,只對上述問題簡單描述:
這裡寫圖片描述


(網上某位大神畫的圖,因為是之前下載的,現在找不到作者了,引用一下,說明問題,切莫見怪)

上面的圖畫的很清楚:
(1)桌面Launcher應用收到點選事件,通過Binder IPC通訊呼叫AMS中的startActivity;
(2)AMS首先呼叫Process.start()方法,從Zygote程序Fork出一個程序,並將ActivityThread.main函式作為主執行緒的入口,開始執行;
(3)應用程序啟動後,會在ActivityThread.main函式中呼叫attach函式,該函式會遠端呼叫AMS.attachApplication函式,向AMS註冊當前的程序,然後AMS會遠端呼叫應用的ActivityThread.bindApplication函式,建立一些關鍵的資料結構,後面AMS接收到Idle訊息後,經由Binder嚮應用程序傳送LAUNCH_ACTIVITY遠端呼叫,從而開始啟動Activity。
上面的最下面的部分,就是應用一直保持執行狀態的原因,應用程序主執行緒裡面建立了一個Looper迴圈,一直在等待訊息,沒有訊息的時候執行緒會被阻塞住,從而保證主執行緒一直處於活躍狀態。
這裡寫圖片描述


這個圖是Android應用啟動後,整個的程序結構,裡面包含了上面的圖中沒有包含的有關Android系統程序的相關內容,有興趣的可以再研究一下。

2.2 Android訊息機制

網上有很多資料,對於Android訊息機制已經講的很清楚,這裡就不詳細的介紹了,推薦老羅的 http://blog.csdn.net/luoshengyang/article/details/6817933 ,這裡簡單介紹一下Handler、Looper以及MessageQueue之間的關係,看一下圖:
這裡寫圖片描述
分兩種情況來說明整個過程:
情形(1):應用執行緒中的MessageQueue中沒有訊息,執行緒處於阻塞狀態;
情形(2):應用執行緒中MessageQueue中有訊息,執行緒處於執行狀態;

2.2.1 執行緒阻塞

執行緒阻塞的時候,會停止在MessageQueue.next函式中的nativePollOnce裡面,超時時間設定成了-1,假設當前執行緒代號執行緒A,這時候只能由別的執行緒(比如執行緒B)向執行緒A的MessageQueue中enqueueMessage,看一下這個函式:

boolean enqueueMessage(Message msg, longwhen) {
            Message p = mMessages;
            boolean needWake;
            if (p == null || when == 0 || when < p.when) {
                // New head, wake up the event queue if blocked.
                msg.next = p;
                mMessages = msg;
                needWake = mBlocked;
            } else {
                needWake = mBlocked && p.target == null && msg.isAsynchronous();
                Message prev;
                for (;;) {
                    prev = p;
                    p = p.next;
                    if (p == null || when < p.when) {
                        break;
                    }
                    if (needWake && p.isAsynchronous()) {
                        needWake = false;
                    }
                }
                msg.next = p; // invariant: p == prev.next
                prev.next = msg;
            } 
            if (needWake) {
                nativeWake(mPtr);    //喚醒處於阻塞狀態的mPtr所對應的執行緒
            }
        }
        return true;
    }

如果當前執行緒處於阻塞狀態,會呼叫到nativeWake函式,該函式會向native層的MessageQueue、Looper對應的pipe管道中寫入一個W字元,epoll機制在監聽pipe管道讀事件的時候收到資料會從上述阻塞的nativePollOnce函式裡面返回,返回到java層以後發現MessageQueue裡面有未處理的訊息,就可以接著處理了。

2.2.2 執行緒正在執行

一開始以為,如果執行緒處於執行狀態,應該一直處理MessageQueue中的訊息,直到全部都處理完,沒有訊息以後進入阻塞狀態,整個的流程應該不會和native層有任何的關係,但是實際上程式碼不是這樣實現的,執行緒在處理每一個訊息的時候,都會執行native函式nativePollOnce,如果當前MessageQueue裡面有訊息,會將epoll的超時時間設定為0,epoll會立馬返回,這時候就可以從nativePollOnce裡面返回處理下一個訊息,但是像上面的MessageQueue裡面沒有訊息後nativePollOnce在執行的時候,超時時間標記被設定成了-1,在進入epoll之前會用一個很大的時間值來替代-1,從而讓epoll機制無法返回,達到阻塞執行緒的目的。
說明:這個部分,老羅的部落格上將的很清楚,實在不想也沒有必要去細寫了。

3 應用請求VSync同步訊號

應用在請求重繪的時候會請求同步訊號,而且是重繪一次,請求一次,不重繪的時候是不請求的,也就是正常情況下,若應用的介面不請求重繪,應用是接收不到VSync訊號的。應用要想請求同步訊號,可以藉助Choreographer物件來實現,Choreographer的英文含義是“編舞”,是用來控制節奏的,名字起得確實挺生動的。
看一下Choreographer的定義,該類包含一個FrameDisplayEventReceiver物件,看一下程式碼:

 //Choreographer.java
   private final class FrameDisplayEventReceiver extends DisplayEventReceiver implements Runnable {
        private boolean mHavePendingVsync;
        private long mTimestampNanos;
        private int mFrame;

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

        @Override
        publicvoid onVsync(long timestampNanos, int builtInDisplayId, int frame) {
            .............
            mTimestampNanos = timestampNanos;
            mFrame = frame;
            Messagemsg = Message.obtain(mHandler, this);
            msg.setAsynchronous(true);
            mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
        }

        @Override
        publicvoid run() {
            mHavePendingVsync = false;
            doFrame(mTimestampNanos, mFrame);
        }
    }

FrameDisplayEventReceiver這個類比較簡單,主要的工作都在基類DisplayEventReceiver裡面完成了,DisplayEventReceiver類裡面有兩個比較重要的函式,一個是構造器,還有一個就是scheduleVsync函式:

//DisplayEventReceiver.java
public abstract class DisplayEventReceiver {
    private final CloseGuard mCloseGuard = CloseGuard.get(); 
    private long mReceiverPtr; 
    // We keep a reference message queue object here so that it is not
    // GC'd while the native peer of the receiver is using them.
    private MessageQueue mMessageQueue; 
    /**
     * Creates a display event receiver.
     * @param looper The looper to use when invoking callbacks.
     */
    public DisplayEventReceiver(Looper looper) {
        if (looper == null) {
            thrownew IllegalArgumentException("looper must not be null");
        } 
        mMessageQueue = looper.getQueue();
        mReceiverPtr = nativeInit(this, mMessageQueue); 
        mCloseGuard.open("dispose");
    }
    /**
     * 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);
        }
    }
}

該類是一個abstract類,構造器裡面呼叫了nativeInit函式,當應用需要同步訊號的時候,最終會呼叫到scheduleVsync函式,裡面呼叫到了nativeScheduleVsync函式,這兩個函式步驟比較多,下面分別來分析。

3.1 nativeInit

函式定義在android_view_DisplayEventReceiver.cpp裡面:

static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverObj, jobject messageQueueObj) {
    sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
    if (messageQueue == NULL) {
        jniThrowRuntimeException(env, "MessageQueue is not initialized.");
        return 0;
    }
    sp<NativeDisplayEventReceiver> 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
    returnreinterpret_cast<jlong>(receiver.get());
}

(1)獲取與當前應用主執行緒相關聯的native層的MessageQueue物件;
(2)建立一個NativeDisplayEventReceiver物件;
(3)呼叫NativeDisplayEventReceiver.initialize函式;
下面逐個分析上面的2、3兩個步驟。

3.1.1 NativeDisplayEventReceiver

該類定義在android_view_DisplayEventReceiver.cpp檔案中,看一下定義:

class NativeDisplayEventReceiver : public LooperCallback {
public:
    NativeDisplayEventReceiver(JNIEnv* env, jobject receiverObj, const sp<MessageQueue>& messageQueue);
    status_t initialize();
    void dispose();
    status_t scheduleVsync();
protected:
    virtual ~NativeDisplayEventReceiver(); 
private:
    jobject mReceiverObjGlobal;
    sp<MessageQueue> 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);
};

該類包含一個DisplayEventReceiver成員變數,在建立NativeDisplayEventReceiver物件時會建立DisplayEventReceiver物件,看一下DisplayEventReceiver物件的建構函式:

//DisplayEventReceiver.cpp
DisplayEventReceiver::DisplayEventReceiver() {
    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
    if (sf != NULL) {
        mEventConnection = sf->createDisplayEventConnection();
        if (mEventConnection != NULL) {
            mDataChannel = mEventConnection->getDataChannel();
        }
    }
}

上面幾行程式碼是應用程序與SurfaceFlinger程序通訊的連線建立的關鍵函式。逐個函式進行分析,先看ComposerService::getComposerService():

// Get a connection to the Composer Service.  This will block until
// a connection is established. 
//註釋很重要  這是一個static方法獲取單例模式下的BpSurfaceComposer(new BpBinder(handle))物件
/*static*/ sp<ISurfaceComposer> ComposerService::getComposerService() {
    ComposerService& instance = ComposerService::getInstance();
    Mutex::Autolock _l(instance.mLock);
    if (instance.mComposerService == NULL) { 
       //------------------重要---------------------------
        ComposerService::getInstance().connectLocked(); 
        assert(instance.mComposerService != NULL);
        ALOGD("ComposerService reconnected");
    }
    return instance.mComposerService;
}

該函式是一個static函式,ComposerService是一個單例模式,想到單例就應該想到是程序內唯一,首先建立物件ComposerService,然後呼叫該物件的connectLocked()函式:

void ComposerService::connectLocked() {
    const String16 name("SurfaceFlinger"); 
    /*
    (1) sp<ISurfaceComposer> mComposerService;
    這裡getService將mComposerService例項化成一個BpSurfaceComposer物件,定義在ISurfaceComposer.cpp中
    其中這裡的BpSurfaceComposer已經獲得了SurfaceFlinger的service的在binder驅動中的handle值
    mComposerService是一個 BpSurfaceComposer(new BpBinder(handle))物件 
    (2) 這裡的getService作用很明顯,是從ServiceManager程序中查詢"SurfaceFlinger"的Binder對應的handle值,
    返回的out型引數mComposerService對應的就是"SurfaceFlinger" binder 服務端的客戶端Binder物件,通過這個
    mComposerService就可以和"SurfaceFlinger"進行通訊
    */
    while (getService(name, &mComposerService) != NO_ERROR) {
        usleep(250000);
    }
    assert(mComposerService != NULL);

    // Create the death listener.
    classDeathObserver : public IBinder::DeathRecipient {
        ComposerService& mComposerService;
        virtualvoidbinderDied(const wp<IBinder>& who) {
            ALOGW("ComposerService remote (surfaceflinger) died [%p]",
                  who.unsafe_get());
            mComposerService.composerServiceDied();
        }
     public:
        DeathObserver(ComposerService& mgr) : mComposerService(mgr) { }
    };

    mDeathObserver = new DeathObserver(*const_cast<ComposerService*>(this));
    IInterface::asBinder(mComposerService)->linkToDeath(mDeathObserver);
}

上面呼叫了getService函式,該函式是一個模板函式,因此定義在標頭檔案IServiceManager.h裡面:

template<typenameINTERFACE>
status_t getService(const String16& name, sp<INTERFACE>* outService)
{
    const sp<IServiceManager> sm = defaultServiceManager();
    if (sm != NULL) {
        *outService = interface_cast<INTERFACE>(sm->getService(name));
        if ((*outService) != NULL) return NO_ERROR;
    }
    return NAME_NOT_FOUND;
}

1 defaultServiceManager返回的程序範圍內唯一的BpServiceManager,相當於是 sm = new BpServiceManager(new BpBinder(0));
2 sm->getService(name): 會呼叫BpServiceManager中的getService函式,經過binder驅動程式和service_manager守護程序進行通訊,得到service名稱為name的service的handle值,返回的是一個BpBinder(handle)
3 interface_cast(new BpBinder(handle))會建立一個BpINTERFACE物件,
sm返回的是一個BpServiceManager物件,該物件是一個Binder的客戶端,也就是Service_Manager服務守護程序的Bp客戶端,相當於是BpServiceManager(new BpBinder(0)),根據前面的服務名稱”SurfaceFlinger”,最終outService返回的是一個BpSurfaceComposer物件,再看一下SurfaceFlinger的宣告:

class SurfaceFlinger : public BnSurfaceComposer,
                       private IBinder::DeathRecipient,
                       private HWComposer::EventHandler{.....}

根據上面的分析可知,ComposerService::getComposerService()返回的是一個與SurfaceFlinger程序建立Binder程序通訊的客戶端,服務端就SurfaceFlinger物件本身,接下來看DisplayEventReceiver建構函式中的:

 mEventConnection = sf->createDisplayEventConnection(); //BpSurfaceComposer->createDisplayEventConnection()

該函式定義在ISurfaceComposer.cpp檔案中:

    virtual sp<IDisplayEventConnection> createDisplayEventConnection()
    {
        Parcel data, reply;
        sp<IDisplayEventConnection> result;
        int err = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
        if (err != NO_ERROR) {
            return result;
        }
        err = remote()->transact(BnSurfaceComposer::CREATE_DISPLAY_EVENT_CONNECTION, data, &reply);
        if (err != NO_ERROR) {
            ALOGE("ISurfaceComposer::createDisplayEventConnection: error performing "
                    "transaction: %s (%d)", strerror(-err), -err);
            return result;
        }
        result = interface_cast<IDisplayEventConnection>(reply.readStrongBinder());
        return result;
    }

該函式經由BnSurfaceComposer.onTransact函式輾轉呼叫到SurfaceFlinger.createDisplayEventConnection函式:

sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection() {
    return mEventThread->createEventConnection();
}

出現了熟悉的面孔mEventThread,該物件是一個EventThread物件,該物件在SurfaceFlinger.init函式裡面建立,但是建立執行以後,貌似還沒有進行任何的動作,這裡呼叫createEventConnection函式:

sp<EventThread::Connection> EventThread::createEventConnection() const {
    return new Connection(const_cast<EventThread*>(this));
}

有建立了一個EventThread::Connection物件,前面分析到,Connection的建構函式會建立一個BitTube物件,BitTube物件中包含一對互聯的socket,一端傳送另一端就能收到。並將BitTube物件儲存在EventThread::Connection.mChannel裡面。返回到上面DisplayEventReceiver建構函式中的mEventConnection是一個BpDisplayEventConnection物件,看一下EventThread::Connection的定義可以知道Connection是一個BnDisplayEventConnection物件,又是一對Binder客戶端和伺服器,接下來再看mEventConnection->getDataChannel()函式,該函式呼叫鏈:
(1)BpDisplayEventConnection.getDataChannel() //DisplayEventConnection.cpp
(2)BnDisplayEventConnection.onTransact //DisplayEventConnection.cpp
(3)EventThread::Connection.getDataChannel() //EventThread.cpp
先看BnDisplayEventConnection.onTransact函式,該函式先呼叫Connection.getDataChannel()函式返回前面建立的BitTube物件:

status_t BnDisplayEventConnection::onTransact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    switch(code) {
        case GET_DATA_CHANNEL: {
            CHECK_INTERFACE(IDisplayEventConnection, data, reply);
            sp<BitTube> channel(getDataChannel());

            channel->writeToParcel(reply);
            return NO_ERROR;
        }
    }
    return BBinder::onTransact(code, data, reply, flags);
}

上面的channel是一個指向BitTube物件的指標,值得注意的是後面呼叫了BitTube.writeToParcel函式:

status_t BitTube::writeToParcel(Parcel* reply) const
{    if (mReceiveFd < 0)return -EINVAL; 
    status_t result = reply->writeDupFileDescriptor(mReceiveFd);
    close(mReceiveFd);
    mReceiveFd = -1;
    return result;
}

這裡將前面建立BitTube物件時建立的互聯的socket的mReceiveFd接收端的描述符傳遞給了對應的Binder客戶端,也就是步驟(1)中的BpDisplayEventConnection中,同時關閉了Binder服務端的接收端描述符,也就是對應的Bn服務端只負責往Connection的socket中寫入資料,客戶端負責接收資料,在繼續看BpDisplayEventConnection.getDataChannel函式之前,先理一下思路:
(1)應用程式建立了一個Choreographer物件;
(2)Choreographer物件建立了一個FrameDisplayEventReceiver物件,該類繼承了DisplayEventReceiver類;
(3)建立DisplayEventReceiver物件的過程中,呼叫nativeInit函式,建立了native層物件NativeDisplayEventReceiver;
(4)NativeDisplayEventReceiver物件的成員變數mReceiver是一個DisplayEventReceiver物件;
(5)在建立DisplayEventReceiver物件的過程中,通過Service_Manager程序建立了與SurfaceFlinger程序之間的連線,
(6)通過SurfaceFlinger的mEventThread在SurfaceFlinger程序中建立了EventThread::Connection物件,該物件建立了一個BitTube物件,該物件包含一對互聯的socket,並返回了Binder客戶端BpDisplayEventConnection物件;
(7)經由返回的BpDisplayEventConnection物件,獲取步驟6中建立的SurfaceFlinger服務端物件EventThread::Connection中BitTube物件的接收端socket描述符;
接下來看一下對應的BpDisplayEventConnection.getDataChannel函式:

    virtual sp<BitTube> getDataChannel() const {
        Parcel data, reply;
        data.writeInterfaceToken(IDisplayEventConnection::getInterfaceDescriptor());
        remote()->transact(GET_DATA_CHANNEL, data, &reply);
        returnnew BitTube(reply);
    }

該函式呼叫了BpDisplayEventConnection客戶端的transact函式,最終根據返回的Parcel資料建立了一個客戶端的BitTube物件,看一下BitTube的對應的建構函式:

BitTube::BitTube(const Parcel& data) : mSendFd(-1), mReceiveFd(-1){
    mReceiveFd = dup(data.readFileDescriptor());
}

該建構函式從Parcel中讀取前面在SurfaceFlinger程序中寫入的socket接收端的描述符。
到這裡native層的NativeDisplayEventReceiver物件已經建立結束,這時候客戶端程序已經有了一個和SurfaceFlinger服務端相連的socket接收端描述符。

3.1.2 NativeDisplayEventReceiver.initialize

直接看程式碼:

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;
}

這裡的主要程式碼是mMessageQueue->getLooper()->addFd()這一行,其中的引數mReceiver.getFd()返回的是在建立NativeDisplayEventReceiver時從SurfaceFlinger服務端接收回來的socket接收端描述符,前面分析到
mMessageQueue是與當前應用執行緒關聯的java層的MessageQueue對應的native層的MessageQueue物件,下面看一下Looper.addFd這個函式,上面呼叫時傳進來的this指標對應的是一個NativeDisplayEventReceiver物件,該類繼承了LooperCallback:

int Looper::addFd(int fd, int ident, int events, Looper_callbackFunc callback, void* data) {
    return addFd(fd, ident, events, callback ? new SimpleLooperCallback(callback) : NULL, data);
}
int Looper::addFd(int fd, int ident, int events, const sp<LooperCallback>& callback, void* data) { 
    int epollEvents = 0;
    if (events & EVENT_INPUT) epollEvents |= EPOLLIN;
    if (events & EVENT_OUTPUT) epollEvents |= EPOLLOUT;

    { // acquire lock
        AutoMutex _l(mLock);

        Request request;
        request.fd = fd;
        request.ident = ident;
        request.callback = callback;
        request.data = data;

        struct epoll_event eventItem;
        memset(& eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union
        eventItem.events = epollEvents;
        eventItem.data.fd = fd;

        ssize_t requestIndex = mRequests.indexOfKey(fd);
        if (requestIndex < 0) {
            int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, & eventItem);
            if (epollResult < 0) {
            }
            mRequests.add(fd, request);
        } else {
            int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_MOD, fd, & eventItem);
            if (epollResult < 0) {
                return -1;
            }
            mRequests.replaceValueAt(requestIndex, request);
        }
    } // release lock
    return 1;
}

首先將上面傳進來的NativeDisplayEventReceiver物件封裝成一個SimpleLooperCallback物件,呼叫下面的addFd函式的時候主要步驟如下:
(1)建立一個struct epoll_event結構體物件,將對應的記憶體全部用清0,並作對應的初始化;
(2)查詢通過addFd方法已經新增到epoll中監聽的檔案描述符;
(3)查詢不到的話,則呼叫epoll_ctl方法設定EPOLL_CTL_ADD屬性將對應的檔案描述符新增到epoll監聽的描述符中;
(4)根據前面addFd傳入的引數EVENT_INPUT,說明當前應用執行緒的native層的Looper物件中的epoll機制已經開始監聽來自於SurfaceFlinger服務端socket端的寫入事件。
分析到這裡,大概可以猜測,SurfaceFlinger端的垂直同步訊號分發到客戶端程序應該適合當前的這個socket又密切的關係。

3.2 nativeScheduleVsync

該函式經由下面的呼叫路徑呼叫到:
(1)Choreographer.scheduleVsyncLocked
(2)NativeDisplayEventReceiver.scheduleVsync —-> DisplayEventReceiver.scheduleVsync
看一下nativeScheduleVsync函式,該函式定義在android_view_DisplayEventReceiver.cpp檔案中:

static void nativeScheduleVsync(JNIEnv* env, jclass clazz, jlong receiverPtr) {
    sp<NativeDisplayEventReceiver> receiver = reinterpret_cast<NativeDisplayEventReceiver*>(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());
    }
}

首先根據java層傳進來的native層NativeDisplayEventReceiver物件的指標,該native物件就是前面在呼叫nativeInit函式時建立的物件,看函式的名稱,應該是java層想要請求同步訊號,這裡面就有一個問題:同步訊號是週期性的,那麼應用請求同步訊號是隻請求一次呢?還是多次?
呼叫到NativeDisplayEventReceiver::scheduleVsync函式:

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;
}

先跳過這裡的processPendingEvents函式,後面再分析,先分析DisplayEventReceiver.requestNextVsync函式:

status_t DisplayEventReceiver::requestNextVsync() {
    if (mEventConnection != NULL) {
        mEventConnection->requestNextVsync();
        return NO_ERROR;
    }
    return NO_INIT;
}

這裡的mEventConnection也是前面建立native層物件NativeDisplayEventReceiver時建立的,實際物件是一個BpDisplayEventConnection物件,也就是一個Binder客戶端,對應的Binder服務端BnDisplayEventConnection是一個EventThread::Connection物件,對應的BpDisplayEventConnection.requestNextVsync函式和BnDisplayEventConnection.onTransact(REQUEST_NEXT_VSYNC)函式沒有進行特別的處理,下面就呼叫到EventThread::Connection.requestNextVsync函式,從BnDisplayEventConnection.onTransact(REQUEST_NEXT_VSYNC)開始已經從使用者程序將需要垂直同步訊號的請求傳送到了SurfaceFlinger程序,下面的函式呼叫開始進入SF程序:

void EventThread::Connection::requestNextVsync() {
    mEventThread->requestNextVsync(this);
}

輾轉呼叫到EventThread.requestNextVsync函式,注意裡面傳了引數this,也就是當前的EventThread::Connection物件,需要明確的是,這裡的mEventThread物件是建立EventThread::Connection物件的時候儲存的,對應的是SurfaceFlinger物件的裡面的mEventThread成員,該物件是一個在SurfaceFlinger.init裡面建立並啟動的執行緒物件,可見設計的時候就專門用這個SurfaceFlinger.mEventThread執行緒來接收來自應用程序的同步訊號請求,每來一個應用程序同步訊號請求,就通過SurfaceFlinger.mEventThread建立一個EventThread::Connection物件,並通過EventThread.registerDisplayEventConnection函式將建立的EventThread::Connection物件儲存到EventThread.mDisplayEventConnections裡面,上面有呼叫到了EventThread.requestNextVsync函式:

void EventThread::requestNextVsync(const sp<EventThread::Connection>& connection) {
    Mutex::Autolock _l(mLock);
    if (connection->count < 0) {
        connection->count = 0;
        mCondition.broadcast();
    }
}

傳進來的是一個前面建立的EventThread::Connection物件,裡面判斷到了EventThread::Connection.count成員變數,看一下EventThread::Connection建構函式中初始變數的值:

EventThread::Connection::Connection(const sp<EventThread>& eventThread)
    : count(-1), mEventThread(eventThread), mChannel(new BitTube()){
}

可以看到初始值是-1,這個值就是前面那個問題的關鍵,EventThread::Connection.count標示了這次應用程序的垂直同步訊號的請求是一次性的,還是多次重複的,看一下注釋裡面對於這個變數的說明:

        // count >= 1 : continuous event. count is the vsync rate
        // count == 0 : one-shot event that has not fired
        // count ==-1 : one-shot event that fired this round / disabled
        int32_t count;

很清楚的說明了,count = 0說明當前的垂直同步訊號請求是一個一次性的請求,並且還沒有被處理。上面EventThread::requestNextVsync裡面將count設定成0,同時呼叫了mCondition.broadcast()喚醒所有正在等待mCondition的執行緒,這個會觸發EventThread.waitForEvent函式從:

    mCondition.wait(mLock);

中醒來,醒來之後經過一輪do…while迴圈就會返回,返回以後呼叫序列如下:
(1)EventThread::Connection.postEvent(event)
(2)DisplayEventReceiver::sendEvents(mChannel, &event, 1),mChannel引數就是前面建立DisplayEventReceiver是建立的BitTube物件
(3)BitTube::sendObjects(dataChannel, events, count),static函式,通過dataChannel指向BitTube物件
最終呼叫到BitTube::sendObjects函式:

ssize_t BitTube::sendObjects(const sp<BitTube>& tube, void const* events, size_t count, size_t objSize){
    const char* vaddr = reinterpret_cast<const char*>(events);
    ssize_t size = tube->write(vaddr, count*objSize);
    return size < 0 ? size : size / static_cast<ssize_t>(objSize);
}

繼續呼叫到BitTube::write函式:

ssize_t BitTube::write(void const* vaddr, size_t size){
    ssize_t err, len;
    do {
        len = ::send(mSendFd, vaddr, size, MSG_DONTWAIT | MSG_NOSIGNAL);
        // cannot return less than size, since we're using SOCK_SEQPACKET
        err = len < 0 ? errno : 0;
    } while (err == EINTR);
    return err == 0 ? len : -err;
}

這裡呼叫到了::send函式,::是作用域描述符,如果前面沒有類名之類的,代表的就是全域性的作用域,也就是呼叫全域性函式send,這裡很容易就能想到這是一個socket的寫入函式,也就是將event事件資料寫入到BitTube中互聯的socket中,這樣在另一端馬上就能收到寫入的資料,前面分析到這個BitTube的socket的兩端連線著SurfaceFlinger程序和應用程序,也就是說通過呼叫BitTube::write函式,將最初由SurfaceFlinger捕獲到的垂直訊號事件經由BitTube中互聯的socket從SurfaceFlinger程序傳送到了應用程序中BitTube的socket接收端。
下面就要分析應用程序是如何接收並使用這個垂直同步訊號事件的。

3.3 應用程序接收VSync

3.3.1 解析VSync事件

VSync同步訊號事件已經發送到使用者程序中的socket接收端,在上面(3.1.2)NativeDisplayEventReceiver.initialize中分析到應用程序端的socket接收描述符已經被新增到Choreographer所線上程的native層的Looper機制中,在epoll中監聽EPOLLIN事件,當socket收到資料後,epoll會馬上返回,下面分步驟看一下Looper.pollInner函式:
(1)epoll_wait

    struct epoll_event eventItems[EPOLL_MAX_EVENTS];
    int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);

在監聽到描述符對應的事件後,epoll_wait會馬上返回,並將產生的具體事件型別寫入到引數eventItems裡面,最終返回的eventCount是監聽到的事件的個數
(2)事件分析

    for (int i = 0; i < eventCount; i++) {
        int fd = eventItems[i].data.fd;
        uint32_t epollEvents = eventItems[i].events;
        if (fd == mWakeReadPipeFd) {   //判斷是不是pipe讀管道的事件   這裡如果是EventThread,這裡就是一個socket的描述符,而不是mWakeReadPipeFd
            if (epollEvents & EPOLLIN) {
                awoken(); // 清空讀管道中的資料
            } else {
                ALOGW("Ignoring unexpected epoll events 0x%x on wake read pipe.", epollEvents);
            }
        } else {
           //EventThread接收到同步訊號走的這裡
            ssize_t requestIndex = mRequests.indexOfKey(fd);
            if (requestIndex >= 0) {
                int events = 0;
                if (epollEvents & EPOLLIN) events |= EVENT_INPUT;
                if (epollEvents & EPOLLOUT) events |= EVENT_OUTPUT;
                if (epollEvents & EPOLLERR) events |= EVENT_ERROR;
                if (epollEvents & EPOLLHUP) events |= EVENT_HANGUP;
                pushResponse(events, mRequests.valueAt(requestIndex));
            } else {
                ALOGW("Ignoring unexpected epoll events 0x%x on fd %d that is "
                        "no longer registered.", epollEvents, fd);
            }
        }
    }

Looper目前瞭解到的主要監聽的檔案描述符種類有兩種:
1)訊息事件,epoll_wait監聽pipe管道的接收端描述符mWakeReadPipeFd
2)與VSync訊號,epoll_wait監聽socket接收端描述符,並在addFd的過程中將相關的資訊封裝在一個Request結構中,並以fd為key儲存到了mRequests中,具體可以回過頭看3.1.2關於addFd的分析;
因此,上面走的是else的分支,辨別出當前的事件型別後,呼叫pushResponse:

void Looper::pushResponse(int events, const Request& request) {
    Response response;
    response.events = events;
    response.request = request;  //複製不是引用,呼叫拷貝建構函式
    mResponses.push(response);
}

該函式將Request和events封裝在一個Response物件裡面,儲存到了mResponses裡面,也就是mResponses裡面放的是“某某fd上接收到了類別為events的時間”記錄,繼續向下看Looper.pollInner函式
(3)事件分發處理

    // Invoke all response callbacks.
    for (size_t i = 0; i < mResponses.size(); i++) {
        Response& response = mResponses.editItemAt(i);
        if (response.request.ident == POLL_CALLBACK) {
            int fd = response.request.fd;
            int events = response.events;
            void* data = response.request.data;
            int callbackResult = response.request.callback->handleEvent(fd, events, data);
            if (callbackResult == 0) {
                removeFd(fd);
            }
            // Clear the callback reference in the response structure promptly because we
            // will not clear the response vector itself until the next poll.
            response.request.callback.clear();
            result = POLL_CALLBACK;
        }
    }

這裡的response.request是從pushResponse裡面複製過來的,裡面的request對應的Request物件是在addFd的時候建立的,ident成員就是POLL_CALLBACK,所以繼續走到response.request.callback->handleEvent這個函式,回憶一下3.1.2裡面的addFd函式,這裡的callback實際上是一個SimpleLooperCallback(定義在Looper.cpp中)物件,看一下里面的handleEvent函式:

int SimpleLooperCallback::handleEvent(int fd, int events, void* data) {
    return mCallback(fd, events, data);
}

這裡的mCallback就是當時在addFd的時候傳進來的callBack引數,實際上對應的就是NativeDisplayEventReceiver物件本身,因此最終就將垂直同步訊號事件分發到了NativeDisplayEventReceiver.handleEvent函式中。

3.3.2 分發VSync事件

呼叫到NativeDisplayEventReceiver.handleEvent函式,該函式定義在android_view_DisplayEventReceiver.cpp中,直接列出該函式:

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=%" PRId64 ", id=%d, count=%d",
                this, vsyncTimestamp, vsyncDisplayId, vsyncCount);
        mWaitingForVsync = false;
        dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount);
    }
    return 1; // keep the callback
}

首先判斷事件是不是正確的Looper::EVENT_INPUT事件,然後呼叫到NativeDisplayEventReceiver.processPendingEvents函式:

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) {
        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;
}

這裡的mReceiver也就是前面建立NativeDisplayEventReceiver物件是建立的成員變數物件DisplayEventReceiver,下面呼叫到DisplayEventReceiver.getEvents函式,應該是要從出現同步訊號事件的socket中讀取資料,上面Looper機制中epoll中監聽到socket以後,返回到NativeDisplayEventReceiver.handleEvent裡面,但是socket裡面的資料還沒有讀取,下面的呼叫流程為:
(1)mReceiver.getEvents(buf, EVENT_BUFFER_SIZE) —-> DisplayEventReceiver::getEvents(DisplayEventReceiver::Event* events, size_t count)
(2)BitTube::recvObjects(dataChannel, events, count) —-> BitTube::recvObjects(const sp& tube, void* events, size_t count, size_t objSize)
看一下這個recvObjects函式:

ssize_t BitTube::recvObjects(const sp<BitTube>& tube, void* events, size_t count, size_t objSize)
{
    char* vaddr = reinterpret_cast<char*>(events);
    ssize_t size = tube->read(vaddr, count*objSize);
    return size < 0 ? size : size / static_cast<ssize_t>(objSize);
}

這裡在NativeDisplayEventReceiver中建立了一個緩衝區,並在recvObjects中將socket中的Event資料讀到這個緩衝區中,這個Event.header.type一般都是DISPLAY_EVENT_VSYNC,因此在上面的processPendingEvents函式中會將Event資料儲存在outCount所指向的記憶體中,並返回true。 接下來返回到NativeDisplayEventReceiver.handleEvent後會呼叫到dispatchVsync函式:

void NativeDisplayEventReceiver::dispatchVsync(nsecs_t timestamp, int32_t id, uint32_t count) {
    JNIEnv* env = AndroidRuntime::getJNIEnv();
    env->CallVoidMethod(mReceiverObjGlobal, gDisplayEventReceiverClassInfo.dispatchVsync, timestamp, id, count);
    mMessageQueue->raiseAndClearException(env, "dispatchVsync");
}

這裡的處理很直接,直接呼叫mReceiverObjGlobal物件在gDisplayEventReceiverClassInfo.dispatchVsync中指定的函式,將後面的timestamp(時間戳) id(裝置ID) count(經過的同步訊號的數量,一般沒有設定取樣頻率應該都是1),下面分別看一下mReceiverObjGlobal以及gDisplayEventReceiverClassInfo.dispatchVsync代表的是什麼?
(1)mReceiverObjGlobal

NativeDisplayEventReceiver::NativeDisplayEventReceiver(JNIEnv* env, jobject receiverObj, const sp<MessageQueue>& messageQueue) :
        mReceiverObjGlobal(env->NewGlobalRef(receiverObj)), mMessageQueue(messageQueue), mWaitingForVsync(false) {
    ALOGV("receiver %p ~ Initializing input event receiver.", this);
}<