Android VSync事件分發過程原始碼分析
阿新 • • 發佈:2019-01-07
在上一篇文章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則是資料傳輸通道。
這裡只是簡單地構造一個Connection物件,Connection物件的構造過程如下:sp<EventThread::Connection> EventThread::createEventConnection() const { return new Connection(const_cast<EventThread*>(this)); }
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了。