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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章