1. 程式人生 > >Android VSync事件分發過程原始碼分析

Android VSync事件分發過程原始碼分析

在上一篇文章Android VSync訊號產生過程原始碼分析中分別介紹了VSync的兩種產生方式,無論是通過硬體中斷產生還是通過軟體模擬產生,VSync事件最終都會交給EventThread執行緒來分發給所有VSync事件接收者。VSync事件接收者有很多,SurfaceFlinger就是其中一個重要的VSync事件接收者。那麼EventThread執行緒是如何知道該將VSync分發給誰呢?EventThread執行緒有是如何將VSync事件分發給所有VSync事件接收者的呢?本文就針對這兩個問題展開分析。我們知道VSync事件是由EventThread執行緒分發,而VSync事件接收者可能與EventThread執行緒同屬一個程序,也可能分屬不同的程序,這裡就設計跨程序通訊了,Android對VSync事件的分發採用Socket通訊方式。


EventThread執行緒分發VSync事件

事件連線建立過程


對VSYNC等事件感興趣的物件,比如MessageQueue,首先要通過EventThread::createEventConnection()來建立一個連線,實際上就是生成了一個EventThread::Connection物件,Connection只是雙方業務上連線,而BitTube則是資料傳輸通道。

sp<EventThread::Connection> EventThread::createEventConnection() const {
    return new Connection(const_cast<EventThread*>(this));
}
這裡只是簡單地構造一個Connection物件,Connection物件的構造過程如下:
EventThread::Connection::Connection(const sp<EventThread>& eventThread)
    : count(-1), mEventThread(eventThread), mChannel(new BitTube())
{
}
在構造Connection物件時,構造了一個BitTube物件來初始化Connection物件的成員變數mChannel,從上圖可以看出,BitTube類只是對Socket通訊方式的封裝,BitTube物件的構造過程如下:
BitTube::BitTube(): mSendFd(-1), mReceiveFd(-1)
{
    int sockets[2];
    if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets) == 0) {
        int size = SOCKET_BUFFER_SIZE;
        setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &size, sizeof(size));
        setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
        setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &size, sizeof(size));
        setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
        fcntl(sockets[0], F_SETFL, O_NONBLOCK);
        fcntl(sockets[1], F_SETFL, O_NONBLOCK);
        mReceiveFd = sockets[0];
        mSendFd = sockets[1];
    } else {
        mReceiveFd = -errno;
        ALOGE("BitTube: pipe creation failed (%s)", strerror(-mReceiveFd));
    }
}

事件連線註冊過程

當Connection物件第一次被強引用時,自動呼叫onFirstRef()函式來初始化該物件。

void EventThread::Connection::onFirstRef() {
    mEventThread->registerDisplayEventConnection(this);
}
在onFirstRef()函式裡主動呼叫EventThread::registerDisplayEventConnection()把自己加入到EventThread的成員變數mDisplayEventConnections中,mDisplayEventConnections是一個向量型別,儲存所有需要接收VSync訊號的連線Connection,這樣EventThread執行緒在分發VSync事件時,就知道將VSync事件分發給誰了。對VSYNC訊號感興趣的人,通過registerDisplayEventConnection()函式將連線Connection註冊到EventThread中。
status_t EventThread::registerDisplayEventConnection(
        const sp<EventThread::Connection>& connection) {
    Mutex::Autolock _l(mLock);
	//僅僅將註冊的Connection新增到EventThread的成員變數mDisplayEventConnections中
    mDisplayEventConnections.add(connection);
    mCondition.broadcast();
    return NO_ERROR;
}
EventThread的成員變數mDisplayEventConnections用於記錄所有註冊的Connection連線。

VSync事件分發過程

VSync事件最終在EventThread執行緒執行體threadLoop()中分發給各個監聽者。
bool EventThread::threadLoop() {
    nsecs_t timestamp;
    DisplayEventReceiver::Event vsync;
	//定義displayEventConnections向量,用於儲存所有需要接收VSync事件的連線
    Vector< wp<EventThread::Connection> > displayEventConnections;
    do {
        Mutex::Autolock _l(mLock);
		//判斷是否上報VSync
        do {
            // latch VSYNC event if any
            timestamp = mVSyncTimestamp;
            mVSyncTimestamp = 0;
            //標示是否有客戶端在等待VSync事件
            bool waitForNextVsync = false;
            size_t count = mDisplayEventConnections.size();
            for (size_t i=0 ; i<count ; i++) {
                sp<Connection> connection = mDisplayEventConnections.itemAt(i).promote();
				// 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
				// count ==-2 : one-shot event that fired the round before
                if (connection!=0 && connection->count >= 0) {
                    // at least one continuous mode or active one-shot event
                    waitForNextVsync = true;
                    break;
                }
            }
            if (timestamp) {
                if (!waitForNextVsync) {
                    //接收到VSync事件,但當前沒有客戶端需要接收VSync事件,所以關閉VSync事件源
                    disableVSyncLocked();
                } else {
                    //如果有客戶需要接收VSync事件,則跳出此迴圈,進入VSync事件分發階段
                    break;
                }
            } else {
				//等待接收VSync事件,並重新評估是否需要分發該事件或者是否需要關閉VSync事件源
                if (waitForNextVsync) {
                    //如果有客戶端需要接收VSync事件,則開啟VSync事件源
                    enableVSyncLocked();
                }
            }
            //等待VSync事件
            if (mUseSoftwareVSync && waitForNextVsync) {
                // h/w vsync cannot be used (screen is off), so we use
                // a  timeout instead. it doesn't matter how imprecise this
                // is, we just need to make sure to serve the clients
                if (mCondition.waitRelative(mLock, ms2ns(16)) == TIMED_OUT) {
                    mVSyncTimestamp = systemTime(SYSTEM_TIME_MONOTONIC);
                }
            } else {
                mCondition.wait(mLock);
            }
        } while(true);
        //當需要分發VSync時,跳出上面的while迴圈,
        mDeliveredEvents++;
        mLastVSyncTimestamp = timestamp;
        // now see if we still need to report this VSYNC event
        const size_t count = mDisplayEventConnections.size();
		//遍歷已註冊的所有Connection,將需要接收VSync的Connection新增到displayEventConnections向量中
        for (size_t i=0 ; i<count ; i++) {
            bool reportVsync = false;
            sp<Connection> connection = mDisplayEventConnections.itemAt(i).promote();
			//如果當前Connection已經死亡,則遍歷下一個註冊的Connection
            if (connection == 0)
                continue;
            const int32_t count = connection->count;
            if (count >= 1) {
                if (count==1 || (mDeliveredEvents % count) == 0) {
                    // continuous event, and time to report it
                    reportVsync = true;
                }
            } else if (count >= -1) {
                if (count == 0) {
                    // fired this time around
                    reportVsync = true;
                }
                connection->count--;
            }
            if (reportVsync) {
                displayEventConnections.add(connection);
            }
        }
    } while (!displayEventConnections.size());
    //如果向量displayEventConnections的大小大於0,則將VSync訊號分發給displayEventConnections中的Connection
	//定義即將分發的VSync事件
    vsync.header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
    vsync.header.timestamp = timestamp;
    vsync.vsync.count = mDeliveredEvents;
    const size_t count = displayEventConnections.size();
	//遍歷displayEventConnections中的所有Connection
    for (size_t i=0 ; i<count ; i++) {
        sp<Connection> conn(displayEventConnections[i].promote());
        // make sure the connection didn't die
        if (conn != NULL) {
			//傳送VSync事件
            status_t err = conn->postEvent(vsync);
            if (err == -EAGAIN || err == -EWOULDBLOCK) {
				//這兩個錯誤是指對方當前不接受事件,有可能是事件已滿,放棄這次操作,不作處理
            } else if (err < 0) {
                //事件傳送錯誤,則從Connection註冊列表mDisplayEventConnections中移除該Connection
                removeDisplayEventConnection(displayEventConnections[i]);
            }
        } else {
            //Connection為空,則從Connection註冊列表mDisplayEventConnections中移除該Connection
            removeDisplayEventConnection(displayEventConnections[i]);
        }
    }
    //VSync事件分發完畢,清空displayEventConnections向量
    displayEventConnections.clear();
    return true;
}
在EventThread執行緒中,通過遍歷連線註冊列表mDisplayEventConnections,將VSync事件分發給已註冊,並且需要接收VSync事件的Connection。呼叫各個Connection的postEvent()函式來發送一個VSync事件:
status_t EventThread::Connection::postEvent(const DisplayEventReceiver::Event& event) {
    ssize_t size = DisplayEventReceiver::sendEvents(mChannel, &event, 1);
    return size < 0 ? status_t(size) : status_t(NO_ERROR);
}
引數event描述的是一個VSync事件,Connection的成員變數mChannel指向BitTube物件,通過已建立的BitTube傳輸通道來發送VSync事件Event資訊。
ssize_t DisplayEventReceiver::sendEvents(const sp<BitTube>& dataChannel,Event const* events, size_t count)
{
    return BitTube::sendObjects(dataChannel, events, count);
}
呼叫BitTube類的sendObjects()函式來發送一個VSync事件資訊
ssize_t BitTube::sendObjects(const sp<BitTube>& tube,void const* events, size_t count, size_t objSize)
{
    ssize_t numObjects = 0;
    for (size_t i=0 ; i<count ; i++) {
        const char* vaddr = reinterpret_cast<const char*>(events) + objSize * i;
        ssize_t size = tube->write(vaddr, objSize);
        if (size < 0) {
            // error occurred
            return size;
        } else if (size == 0) {
            // no more space
            break;
        }
        numObjects++;
    }
    return numObjects;
}
該函式可以傳送多個事件物件,對於每一個事件物件的傳送使用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);
        err = len < 0 ? errno : 0;
    } while (err == EINTR);
    return err == 0 ? len : -err;
}
這裡就採用BitTube物件中建立的Socket來發送一個事件資訊。因此EventThread執行緒分發VSync事件是通過在Socket傳送端mSendFd寫入一個Event事件資訊,這樣對於監聽在Socket接收端的VSync接收者就可以收到VSync事件資訊Event了。