Native世界的Handler

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值