Native世界的Handler
在之前一篇文章裏,曾講過,Handler機制在Java有一套框架,在Native世界裏也有一套。現在來分析Native 世界的Handler是怎麼運作,先看下類圖。
角色和Java世界差不多,但是沒有MessageQueue,這個後面分析。先找個切入點,那麼就以nativePollOnce爲切入點。
nativePollOnce的方法在android_os_MessageQueue.cpp定義。代碼如下:
static void android_os_MessageQueue_nativePollOnce(JNIEnv* env, jobject obj,
jlong ptr, jint timeoutMillis) {
NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
nativeMessageQueue->pollOnce(env, obj, timeoutMillis);
}
接着進入pollOnce方法
void NativeMessageQueue::pollOnce(JNIEnv* env, jobject pollObj, int timeoutMillis) {
mPollEnv = env;
mPollObj = pollObj;
//關鍵代碼,掉用Looper的pollOnce,用epoll機制,實現等待喚醒操作
mLooper->pollOnce(timeoutMillis);
mPollObj = NULL;
mPollEnv = NULL;
if (mExceptionObj) {
env->Throw(mExceptionObj);
env->DeleteLocalRef(mExceptionObj);
mExceptionObj = NULL;
}
}
這個mLooper的類型是Looper,具體是在NativeMessageQueue構造方法中初始化.
NativeMessageQueue::NativeMessageQueue() :
mPollEnv(NULL), mPollObj(NULL), mExceptionObj(NULL) {
mLooper = Looper::getForThread();
if (mLooper == NULL) {
mLooper = new Looper(false);
Looper::setForThread(mLooper);
}
}
Looper定義在system/core/libutils/Looper.cpp,具體看pollonce怎麼實現的。
int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
int result = 0;
for (;;) {
......
if (result != 0) {
#if DEBUG_POLL_AND_WAKE
ALOGD("%p ~ pollOnce - returning result %d", this, result);
#endif
if (outFd != NULL) *outFd = 0;
if (outEvents != NULL) *outEvents = 0;
if (outData != NULL) *outData = NULL;
return result;
}
result = pollInner(timeoutMillis);
}
}
也是個死循環,循環跳出條件是result!=0,接着看pollInner,這個方法足有150多行,就不貼所有代碼了,分析幾個關鍵點。
int Looper::pollInner(int timeoutMillis) {
...
**int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);**
...
for (int i = 0; i < eventCount; i++) {
int fd = eventItems[i].data.fd;
uint32_t epollEvents = eventItems[i].events;
if (fd == mWakeEventFd) {
if (epollEvents & EPOLLIN) {
awoken();
} else {
ALOGW("Ignoring unexpected epoll events 0x%x on wake event fd.", epollEvents);
}
} else {
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);
}
}
}
Done: ;
// Invoke pending message callbacks.
...
return result;
}
核心代碼就是調用epoll_wait,等待管道事件的到來,熟悉linux的朋友知道,這個是多路複用IO接口select/poll的增強版本,思想有點類似socket的nio。如果沒有事件發生,則阻塞等待,直到超時。那如何給這個mEpollFd添加事件呢。首先是Java層的MessageQueue調用nativeWake(long ptr);這個ptr其實就是native層MessageQueue對象的指針,最終調用Looper.wake方法。
void Looper::wake() {
#if DEBUG_POLL_AND_WAKE
ALOGD("%p ~ wake", this);
#endif
uint64_t inc = 1;
ssize_t nWrite = TEMP_FAILURE_RETRY(write(mWakeEventFd, &inc, sizeof(uint64_t)));
if (nWrite != sizeof(uint64_t)) {
if (errno != EAGAIN) {
ALOGW("Could not write wake signal, errno=%d", errno);
}
}
}
調用write方法,往mWakeEventFd寫入一個1,mWakeEventFd和mEpollFd關聯,最後從epoll_wait返回。這裏不細講epoll機制,我也是查各種資料,epoll機制看這裏,到此這裏已經講java層和native層的關聯上了,那麼native的作用僅僅是用epoll機制實現阻塞和喚醒嗎,顯然不是,要是的話用java的Lock就可以了。那麼native的message機制用來幹什麼呢。這裏舉一個場景。native層按鍵事件的分發。會用到Looper的一系列方法。
下一偏文章將利用native的handller,寫一個demo,體驗下native的事件通信。