1. 程式人生 > >Looper 監聽檔案描述符

Looper 監聽檔案描述符

還是以SurfaceFlinger為例論述。SurfaceFlinger的init方法會呼叫MessageQueue的setEventThread方法建立Connection物件,並且還會呼叫Looper的addFd方法將BitTube物件的檔案描述符新增到Looper中進行監聽,

mEventThread = eventThread;
mEvents = eventThread->createEventConnection();
mEvents->stealReceiveChannel(&mEventTube);
mLooper->addFd(mEventTube.getFd(), 0, Looper::EVENT_INPUT,
    MessageQueue::cb_eventReceiver, this);

也就是說,一旦BitTube物件的檔案描述符發生變化,就會回撥MessageQueuecb_eventReceiver方法。

Looper的addFd方法呼叫流程圖如下,


Looper中有2個addFd方法,

return addFd(fd, ident, events, callback ? new SimpleLooperCallback(callback) : NULL, data);

如果callback不為空,就構造SimpleLooperCallback物件, SimpleLooperCallback 是Looper.cpp中的一個類,其構造方法如下,

SimpleLooperCallback::SimpleLooperCallback(Looper_callbackFunc callback) :
        mCallback(callback) {
}

將回調方法賦值給mCallback變數, Looper.h中的mCallback宣告如下,

Looper_callbackFunc mCallback;

addFd方法邏輯如下,

1,為結構體Request 賦值,主要儲存檔案描述符,回撥方法等,

Request request;
request.fd = fd;
request.ident = ident;
request.events = events;
request.seq = mNextRequestSeq++;
request.callback = callback;
request.data = data;

Request 結構體定義在Looper.h中。

2,呼叫系統的epoll_ctl 方法新增到epoll監控中,並且將request結構體物件新增到mRequests列表中。

int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_MOD, fd, & eventItem);
•••
mRequests.add(fd, request);

根據Looper機制,訊息處理最後會呼叫Looper的pollOnce方法,該方法處理回撥流程圖如下,


pollInner方法主要邏輯如下,

1,呼叫系統的epoll_wait方法等待epoll事件的到來,也就是BitTube 對應檔案值發生變化,

int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);

2,呼叫SimpleLooperCallback的handleEvent方法進行回撥處理,

int callbackResult = response.request.callback->handleEvent(fd, events, data);

SimpleLooperCallback的handleEvent方法如下,

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

直接呼叫回撥方法。此回撥方法就是通過addFd方法設定的回撥方法。

在此,需要記住的是,通過呼叫Looper的addFd方法設定方法的回撥,如果檔案描述符發生變化,就會呼叫回撥方法。

在SurfaceFlinger中,

mLooper->addFd(mEventTube.getFd(), 0, Looper::EVENT_INPUT,
    MessageQueue::cb_eventReceiver, this);

一旦BitTube對應檔案值發生變化,就會回撥MessageQueue的cb_eventReceiver方法。

除了SurfaceFlinger 使用了這種機制之外,在android系統中,還有很多地方都使用了這個機制。