Android源码探究:Android Native层消息机制完全解析

前言

前文详细分析了Java层的消息循环机制的工作原理,在分析MessageQueue的过程中,我们遇到了nativePollOnce()nativeWake()方法的调用,下面我们就深入到Native层的消息机制来看看它背后的运作原理。

Native层的消息机制

一、NativeMessageQueue的相关逻辑
1、NativeMessageQueue的构建
首先,我们来看看Java层的MessageQueue的构造函数:

    MessageQueue(boolean quitAllowed) {
        mQuitAllowed = quitAllowed;
        mPtr = nativeInit();
    }

这里调用了一个native方法,实际上这里初始化了native层的消息队列,并返回了该消息队列的头部指针地址。由于这个是native方法,这里利用了JNI机制调用本地代码,JNI的相关知识笔者在前面的文章也有说到,这里就不再赘述。我们直接来看本地代码:(frameworks/base/core/jni/android_os_MessageQueue.cpp):

static jlong android_os_MessageQueue_nativeInit(JNIEnv* env, jclass clazz) {
    NativeMessageQueue* nativeMessageQueue = new NativeMessageQueue();  //创建了一个本地的消息队列
    if (!nativeMessageQueue) {
        jniThrowRuntimeException(env, "Unable to allocate native queue");
        return 0;
    }

    nativeMessageQueue->incStrong(env); //增加强引用指针计数,这里与RefBase,类似于智能指针的概念
    return reinterpret_cast<jlong>(nativeMessageQueue); //强制类型转换,返回jlong类型,实际上是指针的值
}

这里引入了NativeMessageQueue,顾名思义,这应该是native层的消息队列,我们用UML类图来看看它的类结构:

NativeMessageQueue类结构

其中,RefBase是基类,它的作用比较特殊,在Android的native代码中,大部分的类都是继承自RefBase,作用有点类似于Java中的Object。实际上,它的作用与实现智能指针有关,便于native层的垃圾回收的实现(因为C++没有GC机制,我们需要手动实现对象的创建和回收操作)。这里不对RefBase做过多的深究,我们把关注点放回NativeMessageQueue

NativeMessageQueue是native层的消息队列,虽然它称作消息队列,但实际上它是一个空壳,它内部并没有维护消息的队列或者链表,它把涉及消息的相关操作都交给了Looper去处理。与Java层一样的是,一条线程只会有一个Looper,这是因为native层也有着一套线程独立变量的机制,当前线程的变量只与当前线程有关。我们来看看NativeMessageQueue的构造方法:

NativeMessageQueue::NativeMessageQueue() :
        mPollEnv(NULL), mPollObj(NULL), mExceptionObj(NULL) {
    mLooper = Looper::getForThread();  //获取当前线程的Looper对象
    if (mLooper == NULL) {  //如果没有,那么初始化Looper对象
        mLooper = new Looper(false);
        Looper::setForThread(mLooper);  //Looper与当前线程绑定
    }
}

通过NativeMessageQueue的构造方法可以看出,这里实例化了一个Looper,而这个Looper则是与线程相关的,因此我们可以推测Looper实际上承担了消息队列的实际功能,NativeMessageQueue对外表现为消息队列,也有相关的方法,但实际上它把核心逻辑都移交给了Looper去处理。

小结:Java层的MessageQueue被创建的时候,同时会创建一个Native层的NativeMessageQueue,并初始化一个native的Looper。经过JNI的调用返回,NativeMessageQueue对象的指针地址会返回给Java层的MessageQueue,保存在mPtr这个成员变量内。

2、NativeMessageQueue#pollOnce
经过上面的NativeMessageQueue的初始化后,我们就能正常使用它了。还记得我们在Java层的MessageQueue#next()方法内曾经看到过这个调用吗?nativePollOnce(ptr, nextPollTimeoutMillis),这里调用了native的方法,我们来看看它的nativec层的源码:

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);
}

方法很简单,这里传进来的ptr参数实际上就是MessageQueue.mPtr变量,经过强制类型转换后,把ptr转换成了NativeMessageQueue指针,然后调用这个对象的pollOnce(args)方法。这个过程可以理解为:在某一线程内,Java层持有Native层的NativeMessageQueue的指针地址值,经过JNI调用把该地址传递过来,native层根据这个地址找到了这个对象,强制类型转换成了NativeMessageQueue对象。简单地说,Java层的MessageQueue对应了Native层的NativeMessageQueue。

下面,我们来看nativeMessageQueue->pollOnce(env, obj, timeoutMillis):

void NativeMessageQueue::pollOnce(JNIEnv* env, jobject pollObj, int timeoutMillis) {
    mPollEnv = env;
    mPollObj = pollObj;
    mLooper->pollOnce(timeoutMillis);  //把逻辑交给Looper去处理
    mPollObj = NULL;
    mPollEnv = NULL;

    if (mExceptionObj) {
        env->Throw(mExceptionObj);  //env是JNI环境,这里的异常会抛给Java层
        env->DeleteLocalRef(mExceptionObj);
        mExceptionObj = NULL;
    }
}

逻辑很简单,这里调用了mLooper->pollOnce(timeoutMillis)方法,并把超时时间传递了进去,结合函数名字,我们可以合理推测:该函数内部在超时时间内进行native的消息处理,达到了超时时间就会JNI调用返回,以便处理Java层的消息。我们先记住这个推测,待会分析Looper的时候再来看这个推测是否正确。

3、NativeMessageQueue#wake
同样地,我们之前在讨论MessageQueue#enqueueMessage()的时候,会发现进行了nativeWake()调用,那么我们直接看源码:

static void android_os_MessageQueue_nativeWake(JNIEnv* env, jclass clazz, jlong ptr) {
    NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
    nativeMessageQueue->wake();
}

void NativeMessageQueue::wake() {
    mLooper->wake();
}

显然,根据ptr找到对应的NativeMessageQueue,然后调用了mLooper->wake(),把逻辑交给了Looper去处理。那么到目前为止,一切问题的关键都指向了Looper,我们开始探究native的Looper吧。

二、native Looper的工作原理
Looper是整个Native层消息机制的核心所在,大部分功能都是Looper完成的。要准确理解native Looper,我们首先就要对它的类结构有个整体的认识,下面笔者给出Looper的UML类图方便读者的理解。

1、native Looper的整体认识
Looper的类结构被定义在/system/core/libutils/include/utils/Looper.h,源码地址为Looper.h。结合类结构,我们可以清晰地画出如下的UML类图:

Looper UML类图

结合Looper.h的源码和上面的UML类图,下面先列举几个与Looper有关的类或成员变量,以便后面的源码阅读。
①mWakeEventFd:用于事件通知的文件描述符,在这里表示唤醒Looper的文件描述符。实际上它指向一个eventfd对象,该对象可以实现事件的等待和通知机制。
②mEpollFd:epoll的句柄,指向一个epoll对象,有关epoll的使用都要经过该句柄。epoll简单来说,是Linux下的一种I/O事件通知机制。epoll监听了eventfd,当该文件描述符的缓冲区为空时,epoll发出可写信号,当文件描述符的缓冲区不空时,发出可读信号。利用这样的机制,能实现线程间的通信。
③MessageEnvelop:内部封装了MessageMessageHandleruptime。其中Message是native层发送的消息,而MessageHandler内部有一个回调函数,当消息接收方接收并处理消息后就会回调该函数。uptime是消息的触发时间。
④Request:封装了fdeventscallback等参数,实际上这是Looper监听的一种特殊消息,可以称之为事件,它是以文件描述符形式存在的。通过addFd(args)把fd添加到epoll的监听队列中,然后封装成Request对象,加入到Looper.mRequest内,然后等待事件的发生。
⑤Response:当epoll侦测到某一fd的缓冲池发生了改变后,Looper会找到该fd对应的Request,把它进一步封装成Response,然后加入mResponse等待Looper处理该消息。

2、Looper的创建与初始化
上面详细讲述了与Looper有关的一些知识,在此基础上我们继续探索Looper的原理,首先,我们从Looper的构造方法看起。(源码位置在:/system/core/libutils/Looper.cpp)

Looper::Looper(bool allowNonCallbacks) :
        mAllowNonCallbacks(allowNonCallbacks), mSendingMessage(false),
        mPolling(false), mEpollFd(-1), mEpollRebuildRequired(false),
        mNextRequestSeq(0), mResponseIndex(0), mNextMessageUptime(LLONG_MAX) {
    mWakeEventFd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);  //创建一个用于唤醒Looper的文件描述符
    LOG_ALWAYS_FATAL_IF(mWakeEventFd < 0, "Could not make wake event fd: %s",
                        strerror(errno));

    AutoMutex _l(mLock);
    rebuildEpollLocked();  //重建一个epoll
}
void Looper::rebuildEpollLocked() {
    // 如果已经有一个epoll了,那么关闭它
    if (mEpollFd >= 0) {
#if DEBUG_CALLBACKS
        ALOGD("%p ~ rebuildEpollLocked - rebuilding epoll set", this);
#endif
        close(mEpollFd);
    }

    // 通过Linux系统调用 创建一个epoll实例
    mEpollFd = epoll_create(EPOLL_SIZE_HINT);
    LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance: %s", strerror(errno));

    struct epoll_event eventItem;      //epoll_event 封装了fd、event等
    memset(& eventItem, 0, sizeof(epoll_event)); // 初始化为0
    eventItem.events = EPOLLIN;        //event:EPOLLIN 表示读事件,即对应的连接可读(缓冲区有值)
    eventItem.data.fd = mWakeEventFd;

    // epoll_ctl 系统调用,这里epoll添加了对mWakeEventFd的监听,
    // 当epoll监听到mWakeEventFd的eventItem出现时,就会通知Looper
    int result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeEventFd, & eventItem);
    LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake event fd to epoll instance: %s",
                        strerror(errno));

    // 对mRequest内的所有fd重新添加epoll监听
    for (size_t i = 0; i < mRequests.size(); i++) {
        const Request& request = mRequests.valueAt(i);
        struct epoll_event eventItem;
        request.initEventItem(&eventItem);

        int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, request.fd, & eventItem);
        if (epollResult < 0) {
            ALOGE("Error adding epoll events for fd %d while rebuilding epoll set: %s",
                  request.fd, strerror(errno));
        }
    }
}

Looper的创建和初始化过程的代码逻辑很清晰,主要是做了以下几件事情:
(1)调用eventfd(args)方法创建一个用于唤醒Looper的文件描述符mWakeEventFd
(2)进行epoll_create(int)系统调用,创建一个epoll,用于轮询IO以及通知Looper有关的fd是否发生了改变,并把epoll句柄保存在mEpollFd内。
(3)进行epoll_ctl(args)系统调用,把mWakeEventFd添加到epoll的监听列表中。
(4)遍历mRequests,把所有通过addFd(args)添加进来的文件描述符fd再次加到这个新的epoll的监听列表内。(旧的epoll已经被close了)

3、发送消息/添加事件监听
我们知道,native层的Looper主要处理两种消息:一个是Message,另一个是eventItem(epoll监听文件描述符fd的变化)。下面我们来了解以下消息的发送过程或事件的添加过程。
(1)Looper#sendMessage

void Looper::sendMessage(const sp<MessageHandler>& handler, const Message& message) {
    nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
    sendMessageAtTime(now, handler, message);
}

void Looper::sendMessageDelayed(nsecs_t uptimeDelay, const sp<MessageHandler>& handler,
        const Message& message) {
    nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
    sendMessageAtTime(now + uptimeDelay, handler, message);
}

void Looper::sendMessageAtTime(nsecs_t uptime, const sp<MessageHandler>& handler,
        const Message& message) {
#if DEBUG_CALLBACKS
    ALOGD("%p ~ sendMessageAtTime - uptime=%" PRId64 ", handler=%p, what=%d",
            this, uptime, handler.get(), message.what);
#endif

    size_t i = 0;
    { // acquire lock
        AutoMutex _l(mLock);

        size_t messageCount = mMessageEnvelopes.size();
        // 在mMessageEnvelopes内寻找消息要插入的位置,条件是msg的uptime要比后者的小,但比前者大
        // 这说明在这个消息列表内,下标越小,消息的触发时间越早
        while (i < messageCount && uptime >= mMessageEnvelopes.itemAt(i).uptime) {
            i += 1;
        }

        MessageEnvelope messageEnvelope(uptime, handler, message);
        mMessageEnvelopes.insertAt(messageEnvelope, i, 1);

        // 如果Looper正在发送消息,那么直接返回。因为Looper在发送完消息后,
        // 会计算下一条消息的触发时间进而处理该消息
        if (mSendingMessage) {
            return;
        }
    } // release lock

    // 如果消息被插入在消息列表头部,立刻唤醒looper
    if (i == 0) {
        wake();
    }
}

发送一个消息时,不但要有Message实例,同时也要有MessageHandler,这是消息被处理的时候进行回调的方法。类似于Java层的Messaeg.callback。紧接着,在把消息添加到消息列表的时候,会进行加锁,防止出现并发错误。如果当前Looper没有在处理消息并且插入的消息放在了列表头部,则需要去唤醒Looper。

(2)Looper#addFd
上面是发送一个消息然后等待Looper的处理,而这个方法则是添加一个文件描述符fd,然后让epoll去监听它的变化,如果产生了变化则会得到Looper的处理。

int Looper::addFd(int fd, int ident, int events, const sp<LooperCallback>& callback, void* data) {
#if DEBUG_CALLBACKS
    ALOGD("%p ~ addFd - fd=%d, ident=%d, events=0x%x, callback=%p, data=%p", this, fd, ident,
            events, callback.get(), data);
#endif

    //省略...

    { // acquire lock
        AutoMutex _l(mLock);

        // 封装成Request对象
        Request request;
        request.fd = fd;
        request.ident = ident;
        request.events = events;
        request.seq = mNextRequestSeq++;
        request.callback = callback;
        request.data = data;
        if (mNextRequestSeq == -1) mNextRequestSeq = 0; // reserve sequence number -1

        struct epoll_event eventItem;
        request.initEventItem(&eventItem);

        ssize_t requestIndex = mRequests.indexOfKey(fd);
        if (requestIndex < 0) {
            // 如果mRequest内没有该Request,那么添加到epoll监听列表内
            int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, & eventItem);
            if (epollResult < 0) {
                ALOGE("Error adding epoll events for fd %d: %s", fd, strerror(errno));
                return -1;
            }
            mRequests.add(fd, request);
        } else {
            // 如果mRequest已经有该Request,那么修改epoll监听列表对应的fd的内容
            int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_MOD, fd, & eventItem);
            if (epollResult < 0) {
                // 异常状态处理
                // 省略...
            }
            mRequests.replaceValueAt(requestIndex, request);    //更新mRequest
        }
    } // release lock
    return 1;
}

首先将fd、LooperCallback、*data等封装成了Request对象,然后经过epoll_ctl系统调用,添加到epoll监听列表内,此时epoll就会对fd进行轮询,如果发生了变化就能得到通知。所以可以通过文件描述符的形式添加到Looper,然后我们在别的线程改变它,那么Looper所在的线程就能就能知道它的改变,然后调用回调方法,这样就实现了线程的切换。

4、Looper的唤醒操作
Looper的唤醒操作指的是,往mWakeEventFd的缓冲区写入一个数字,然后Looper的pollOnce(args)就会获取到该事件的发生,然后可以开始处理消息,否则该方法将会阻塞直到超时。

我们回忆下上一篇文章,在调用Message#enqueueMessage插入一条消息的时候,如果Java的消息队列处于阻塞状态、队列头部是消息屏障以及马上有一个异步消息要处理,那么就会进行nativeWake()的本地调用,然后进一步调用Looper#wake()以唤醒Looper。当native的消息处理完成后,会导致Java层的nativePollOnce()的调用返回,从而让Java层处理消息。因此,Looper#wakeLooper#pollOnce起着重要的桥梁作用,它让Java层和native层的消息机制得以联系和连续运作。

下面,我们来看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) {
            LOG_ALWAYS_FATAL("Could not write wake signal to fd %d: %s",
                    mWakeEventFd, strerror(errno));
        }
    }
}

首先定义了一个64位的整型变量为1,然后通过write()方法,往mWakeEventFd写入1。此时epoll会侦测到这个写入事件,然后就会通知Looper了。

5、Looper处理消息的过程
如果Looper想要运转起来,还需要调用一个方法,那就是pollOnce。该方法驱动了native Looper的消息循环。我们先来看源码:

int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
    int result = 0;
    for (;;) {
        // 先处理被添加到mResponses列表的事件,这些事件都没有callback,
        // 因此只能返回给调用者根据ident去处理
        while (mResponseIndex < mResponses.size()) {
            const Response& response = mResponses.itemAt(mResponseIndex++);
            int ident = response.request.ident;
            if (ident >= 0) {
                int fd = response.request.fd;
                int events = response.events;
                void* data = response.request.data;

                if (outFd != NULL) *outFd = fd;
                if (outEvents != NULL) *outEvents = events;
                if (outData != NULL) *outData = data;
                return ident;
            }
        }

        if (result != 0) {

            if (outFd != NULL) *outFd = 0;
            if (outEvents != NULL) *outEvents = 0;
            if (outData != NULL) *outData = NULL;
            return result;
        }

        result = pollInner(timeoutMillis);  //进一步处理,并传入超时时间
    }
}

int Looper::pollInner(int timeoutMillis) {

    // 调整超时时间,根据当前超时时间和mNextMessageUptime来判断
    // 如果传递进来的超时时间大于mNextMessageUptime,就要把超时时间改成这个触发时间
    // 否则,下一条Message将不能在准确时间内得到处理
    if (timeoutMillis != 0 && mNextMessageUptime != LLONG_MAX) {
        nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
        int messageTimeoutMillis = toMillisecondTimeoutDelay(now, mNextMessageUptime);
        if (messageTimeoutMillis >= 0
                && (timeoutMillis < 0 || messageTimeoutMillis < timeoutMillis)) {
            timeoutMillis = messageTimeoutMillis;
        }
    }

    // Poll.
    int result = POLL_WAKE;
    mResponses.clear();
    mResponseIndex = 0;

    // 表示正在轮询
    mPolling = true;

    // 创建epoll_event数组,以保存epoll结果
    struct epoll_event eventItems[EPOLL_MAX_EVENTS];    
    // 进行系统调用,阻塞式等待,收集在epoll监控的事件中已经发生的事件,超过timeoutMillis则返回
    // 实际上这里epoll监听所有已添加的fd的改变,比如写入了“1”,那么就能收集到该事件
    int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);

    // 取消轮询状态
    mPolling = false;

    // Acquire lock.
    mLock.lock();

    // Rebuild epoll set if needed.
    if (mEpollRebuildRequired) {
        mEpollRebuildRequired = false;
        rebuildEpollLocked();
        goto Done;
    }

    // Check for poll error.
    if (eventCount < 0) {
        if (errno == EINTR) {
            goto Done;
        }
        ALOGW("Poll failed with an unexpected error: %s", strerror(errno));
        result = POLL_ERROR;
        goto Done;
    }

    // Check for poll timeout.
    if (eventCount == 0) {
#if DEBUG_POLL_AND_WAKE
        ALOGD("%p ~ pollOnce - timeout", this);
#endif
        result = POLL_TIMEOUT;
        goto Done;
    }

    // 处理所有在epoll收集到的事件
    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();   //从mWakeEventFd中读取“1”,以便下一次的wake()操作,即清空缓冲区
            } else {
                ALOGW("Ignoring unexpected epoll events 0x%x on wake event fd.", epollEvents);
            }
        } else {
            // 根据已触发的fd事件,找到相应的Request,然后添加到mResponses内
            // 表示该事件已经被监听到,等待处理
            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: ;

    // 处理所有的Message 这里只处理触发时间小于当前时间的,
    // 如果触发时间还没到的消息,等待下一次pollOnce()再处理
    mNextMessageUptime = LLONG_MAX;
    while (mMessageEnvelopes.size() != 0) {
        nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
        const MessageEnvelope& messageEnvelope = mMessageEnvelopes.itemAt(0);
        if (messageEnvelope.uptime <= now) {
            { // obtain handler
                sp<MessageHandler> handler = messageEnvelope.handler;
                Message message = messageEnvelope.message;
                mMessageEnvelopes.removeAt(0);
                mSendingMessage = true;
                mLock.unlock();

                handler->handleMessage(message);  //利用MessageHandler来处理消息,即回调函数  
            } // release handler

            mLock.lock();
            mSendingMessage = false;
            result = POLL_CALLBACK;
        } else {
            // The last message left at the head of the queue determines the next wakeup time.
            mNextMessageUptime = messageEnvelope.uptime;
            break;
        }
    }

    // Release lock.
    mLock.unlock();

    // 处理所有的Response,即已触发的fd事件
    for (size_t i = 0; i < mResponses.size(); i++) {
        Response& response = mResponses.editItemAt(i);
        if (response.request.ident == POLL_CALLBACK) {
            int fd = response.request.fd;
            int events = response.events;
            void* data = response.request.data;

            // 回调callback
            int callbackResult = response.request.callback->handleEvent(fd, events, data);
            if (callbackResult == 0) {
                removeFd(fd, response.request.seq);
            }

            response.request.callback.clear();
            result = POLL_CALLBACK;
        }
    }
    return result;
}

一眼看去,整个pollOncepollInner的代码非常长,但实际上它的逻辑非常地清晰明了,详细的分析已经写在了注释里面,这里简单地总结以下它所作的工作:
(1)在pollOnce方法中,首先会对所有Response中没有callback的事件进行处理,这会返回ident给调用者,让调用者自己去处理这个消息。
(2)在pollInner方法内,首先超时时间的调整操作,这要兼顾到一个常规Message的触发,不能让epoll阻塞过久。
(3)紧接着,进行了epoll_wait系统调用,阻塞式等待epoll返回事件,epoll中监听到的事件会保存在eventItems[EPOLL_MAX_EVENTS]内。如果超时时间到了,就返回。
(4)对所有监听到的事件进行处理,根据事件找到相应的Request,然后封装成Response,等待Looper的处理。
(5)处理所有到达触发事件的常规Message,进行handler的回调。
(6)处理所有Response,进行callback回调。

总结

上面完整地分析了Looper的工作原理和运行机制,现在整理一下所有相关的知识点。
①native Looper在初始化的时候,会创建epoll用以监听文件描述符fd的改变,同时实例化了一个mWakeEventFd,这是用来唤醒Looper的fd,然后把它添加到epoll监听队列内。
②Java层的Looper在loop()的过程中,会调用MessageQueue#next()方法,进而调用nativePollOnce()方法,而该方法又交给Looper#pollOnce处理。这表示Java层的消息在处理之前,会先处理native层的消息,直到JNI调用返回。
③在native Looper的循环过程中,会使用epoll_wait系统调用,阻塞式等待相关的fd事件的发生。然后再处理Message和fd event。
④Looper在阻塞的时候,可以通过wake()方法来唤醒它,通过往mWakeEventFd写入"1",会导致epoll_wait返回,从而取消轮询状态。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,126评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,254评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,445评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,185评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,178评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,970评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,276评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,927评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,400评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,883评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,997评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,646评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,213评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,204评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,423评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,423评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,722评论 2 345

推荐阅读更多精彩内容