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的事件通信。