【Android源碼分析】 Looper和MessageQueue消息機制Java層和Native層源碼分析

前言

消息機制

眾所周知Android是基于消息驅(qū)動的,啟動Activity等一系列操作都是通過消息機制實現(xiàn),在JAVA層消息機制主要由幾個類實現(xiàn):

  • 消息的表示:Message
  • 消息隊列: MessageQueue
  • 消息循環(huán):Looper
  • 消息處理:Handler

在Android 4.2版本之后,在Native層也可以通過消息機制來處理Native層的一些功能,對應(yīng)的兩個主要C++類為Looper和MessageQueue,相關(guān)源碼的文件路徑為(不同版本可能不一樣):

    1. system\core\libutils\Looper.cpp
    2. system\core\include\utils\Looper.h
    3. frameworks\base\core\jni\android_os_MessageQueue.cpp

epoll

在開始源碼分析前,讀者需要對Linux的epoll有一定的了解,epoll是IO多路復(fù)用的機制,I/O多路復(fù)用就是通過一種機制,一個進(jìn)程可以監(jiān)視多個描述符,一旦某個描述符就緒(一般是讀就緒或者寫就緒),能夠通知程序進(jìn)行相應(yīng)的讀寫操作。epoll跟select,poll本質(zhì)上都是同步I/O,因為他們都需要在讀寫事件就緒后自己負(fù)責(zé)進(jìn)行讀寫,也就是說這個讀寫過程是阻塞的,而異步I/O則無需自己負(fù)責(zé)進(jìn)行讀寫,異步I/O的實現(xiàn)會負(fù)責(zé)把數(shù)據(jù)從內(nèi)核拷貝到用戶空間。

epoll有三個接口,在下面的源碼分析會涉及到,具體的接口說明可以參閱下面這篇文章 IO多路復(fù)用之epoll總結(jié)

#include <sys/epoll.h>
int epoll_create(int size);             //創(chuàng)建一個epoll的句柄
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);     //epoll的事件注冊函數(shù)
int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout); //等待事件的產(chǎn)生

Looper成員

這篇文章主要通過消息機制的初始化、消息的發(fā)送、消息循環(huán)和處理三個部分進(jìn)行分析,首先我們先看以下nativce層的Looper.h(位于 system\core\include\utils)的主要成員變量和成員函數(shù),至于為什么只看Looper而不看android_os_MessageQueue,這是因為android_os_MessageQueue最后都是調(diào)用到了Looper類的成員函數(shù),android_os_MessageQueue并沒有很復(fù)雜的邏輯在里面。

Looper.h的主要成員變量和成員函數(shù)如下(可以先看后面源碼分析再回來看這一部分)。


    const bool mAllowNonCallbacks;      //是否允許監(jiān)聽的fd事件沒有回調(diào)函數(shù),Looper初始化設(shè)置為false

    int mWakeEventFd;  // 通過eventfd函數(shù)創(chuàng)建的fd,在epoll中注冊監(jiān)聽,通過向該fd讀寫數(shù)據(jù)從而控制喚醒和阻塞

    int mEpollFd;          //創(chuàng)建epoll成功后保存的epoll的fd,注冊監(jiān)聽和等待IO事件需要用到
    bool mEpollRebuildRequired;     //是否需要重新創(chuàng)建epoll  
    void rebuildEpollLocked();    //重新調(diào)用epoll_create構(gòu)建epoll
    void scheduleEpollRebuildLocked();  //設(shè)置mEpollRebuildRequired為true進(jìn)而進(jìn)行epoll重新創(chuàng)建


//類似于map的KeyedVector對象,存儲epoll監(jiān)聽的其他fd,key為fd,value為保存有fd、回調(diào)函數(shù)等的Request對象
    KeyedVector<int, Request> mRequests; 
    struct Request {     //Request數(shù)據(jù)結(jié)構(gòu)
        int fd;       //文件描述符
        int ident;    
        int events;       //監(jiān)聽的事件
        int seq;
        sp<LooperCallback> callback;   //回調(diào)函數(shù)
        void* data;

        void initEventItem(struct epoll_event* eventItem) const;
    };


    Vector<Response> mResponses;    //保存epoll監(jiān)聽其他fd發(fā)送事件后需要處理的Request對象
    void pushResponse(int events, const Request& request);   //往 mResponses push數(shù)據(jù)
    struct Response {    //Response數(shù)據(jù)結(jié)構(gòu)
        int events;         //發(fā)生的事件
        Request request;    //Request對象
    };


    Vector<MessageEnvelope> mMessageEnvelopes; // Native層的消息隊列
    nsecs_t mNextMessageUptime;      //native層消息隊列下一個需要處理的消息的時間
    void sendMessageAtTime(nsecs_t uptime, const sp<MessageHandler>& handler,
            const Message& message);                //從native層的消息隊列發(fā)送消息
    struct MessageEnvelope {                   //消息的數(shù)據(jù)結(jié)構(gòu)
        MessageEnvelope() : uptime(0) { }

        MessageEnvelope(nsecs_t uptime, const sp<MessageHandler> handler,
                const Message& message) : uptime(uptime), handler(handler), message(message) {
        }

        nsecs_t uptime;
        sp<MessageHandler> handler;
        Message message;
    };


    int pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData);  //調(diào)用pollInner函數(shù)
    int pollInner(int timeoutMillis);        //調(diào)用epoll_wait進(jìn)入阻塞,當(dāng)監(jiān)聽到發(fā)生事件后進(jìn)行處理


    void wake();         //通過往mWakeEventFd寫入數(shù)據(jù)喚醒epoll_wait
    void awoken();    //從mWakeEventFd讀取數(shù)據(jù),在pollInner調(diào)用到


    //向epoll添加需要監(jiān)聽的其他fd
    int addFd(int fd, int ident, int events, Looper_callbackFunc callback, void* data);
    int addFd(int fd, int ident, int events, const sp<LooperCallback>& callback, void* data);

    
    //pollInner和pollOnce可能返回的結(jié)果
    enum {
        POLL_WAKE = -1,
        POLL_CALLBACK = -2,
        POLL_TIMEOUT = -3,
        POLL_ERROR = -4,
    };


   

一、消息機制的初始化

Android應(yīng)用主線程的啟動是在ActivityThread.java的main函數(shù)啟動的,消息機制的初始化和循環(huán)也是在這里開始的。

    public static void main(String[] args) {
        
        //......

        //初始化Looper
        Looper.prepareMainLooper();

        ActivityThread thread = new ActivityThread();
        thread.attach(false);

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }

        if (false) {
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }

        // End of event ActivityThreadMain.
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        //開始Looper循環(huán)
        Looper.loop();

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

主線程通過Looper.prepareMainLooper()函數(shù)初始化Looper, 并通過調(diào)用Looper.loop()開始消息循環(huán)和處理。

    public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }

    private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        //將Looper對象放到ThreadLocal中
        sThreadLocal.set(new Looper(quitAllowed));
    }

在prepareMainLooper()中new一個Looper對象并放到ThreadLocal,在Native的Looper初始化中也是new一個Looper對象并放到線程的本地變量中,在后面的源碼分析中就會看到。

  private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
  }

在Looper的構(gòu)造函數(shù)初始化消息隊列和mThread變量。


    private native static long nativeInit();   //初始化native的Looper的MessageQueue

    MessageQueue(boolean quitAllowed) {
        mQuitAllowed = quitAllowed;
        mPtr = nativeInit();      //調(diào)用nativeInit函數(shù)
    }

在MessageQueue初始化的時候調(diào)用了nativeInit,這是一個Native方法,這也是Native層消息機制初始化的入口。

static jlong android_os_MessageQueue_nativeInit(JNIEnv* env, jclass clazz) {
    NativeMessageQueue* nativeMessageQueue = new NativeMessageQueue();    //創(chuàng)建一個NativeMessageQueue對象
    if (!nativeMessageQueue) {
        jniThrowRuntimeException(env, "Unable to allocate native queue");
        return 0;
    }

    nativeMessageQueue->incStrong(env);
    return reinterpret_cast<jlong>(nativeMessageQueue);
}

nativeInit的源碼位于frameworks\base\core\jni\android_os_MessageQueue.cpp中,函數(shù)初始化了一個NativeMessageQueue類并將NativeMessageQueue對象的指針返回給Java層MessageQueue對象的mPtr成員。

接著再看NativeMessageQueue的構(gòu)造函數(shù)

NativeMessageQueue::NativeMessageQueue() :
        mPollEnv(NULL), mPollObj(NULL), mExceptionObj(NULL) {
    mLooper = Looper::getForThread();
    if (mLooper == NULL) {
        mLooper = new Looper(false);
        Looper::setForThread(mLooper);
    }
}

在NativeMessageQueue的構(gòu)造函數(shù)中也是初始化一個Looper對象,在這里L(fēng)ooper的存儲也是用到了本地存儲(getForThread和setForThread函數(shù)實現(xiàn)),這跟在Java層使用ThreadLocal存儲Looper對象類似。

接下來看Looper::getForThread()和Looper::setForThread(mLooper)是如何將Looper對象進(jìn)行本地存儲:

void Looper::setForThread(const sp<Looper>& looper) {
    sp<Looper> old = getForThread(); // also has side-effect of initializing TLS

    if (looper != NULL) {
        looper->incStrong((void*)threadDestructor);
    }

    //存儲Looper到TLS中
    pthread_setspecific(gTLSKey, looper.get());

    if (old != NULL) {
        old->decStrong((void*)threadDestructor);
    }
}

sp<Looper> Looper::getForThread() {
    int result = pthread_once(& gTLSOnce, initTLSKey);
    LOG_ALWAYS_FATAL_IF(result != 0, "pthread_once failed");
    //獲取Looper的TLS對象
    return (Looper*)pthread_getspecific(gTLSKey);
}

可以看到Looper對象的存儲通過int pthread_setspecific(pthread_key_t key, const void *value) 和 void *pthread_getspecific(pthread_key_t key) 這兩個函數(shù)實現(xiàn),這是linux的 TLS(線程局部存儲),相當(dāng)于Java的ThreadLocal。

接著再看Looper的構(gòu)造函數(shù):

Looper::Looper(bool allowNonCallbacks) :      //初始化過程中mAllowNonCallbacks為false
        mAllowNonCallbacks(allowNonCallbacks), mSendingMessage(false),
        mPolling(false), mEpollFd(-1), mEpollRebuildRequired(false),
        mNextRequestSeq(0), mResponseIndex(0), mNextMessageUptime(LLONG_MAX)
{
    //創(chuàng)建一個eventfd對象,返回的mWakeEventFd是epoll需要監(jiān)聽的文件描述符
    mWakeEventFd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
    LOG_ALWAYS_FATAL_IF(mWakeEventFd < 0, "Could not make wake event fd: %s",
                        strerror(errno));

    AutoMutex _l(mLock);
    rebuildEpollLocked();    //創(chuàng)建epoll對eventfd進(jìn)行監(jiān)聽
}


void Looper::rebuildEpollLocked() {
    // Close old epoll instance if we have one.
    if (mEpollFd >= 0) {
#if DEBUG_CALLBACKS
        ALOGD("%p ~ rebuildEpollLocked - rebuilding epoll set", this);
#endif
        close(mEpollFd);
    }

    //創(chuàng)建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;
    memset(& eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union
    //EPOLLIN :表示監(jiān)聽的文件描述符可以讀
    eventItem.events = EPOLLIN;
    eventItem.data.fd = mWakeEventFd;

    //將mWakeEventFd加入epoll對象的監(jiān)聽文件描述符中并設(shè)置觸發(fā)條件為文件描述符可以讀
    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));

    //epoll對象監(jiān)聽其他的fd
    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的構(gòu)造函數(shù)將傳入的allowNonCallbacks賦值給了mAllowNonCallbacks,可以看到傳入的值為false,這一個值在后面會利用到,標(biāo)識監(jiān)聽的fd允不允許沒有回調(diào)函數(shù)。

Looper的構(gòu)造函數(shù)通過調(diào)用eventfd [關(guān)于eventfd可以戳這里] 創(chuàng)建一個文件描述符來進(jìn)行事件通知,其中通過EFD_NONBLOCK宏設(shè)置該文件描述符的IO為非阻塞,返回的 mWakeEventFd是接下來epoll需要監(jiān)聽的文件描述符。其實在比較早的版本這里是使用管道(pipe)作為epoll監(jiān)聽的對象。

在Native層的Looper使用了 epoll ,通過epoll_create創(chuàng)建了一個epoll對象并將返回的epoll文件描述符保存在mEpollFd,接著再通過epoll_ctl函數(shù)對mWakeEventFd的IO事件進(jìn)行監(jiān)聽,監(jiān)聽事件為EPOLLIN,也就是eventfd有數(shù)據(jù)可以讀。在后面中epoll也對其他fd進(jìn)行監(jiān)聽,在Looper中也提供了Looper.addFd()函數(shù)添加需要epoll需要監(jiān)聽的fd。

接下來分析Looper的兩個函數(shù)addFd函數(shù),分析addFd函數(shù)是因為后面消息循環(huán)和處理會涉及到這些通過addFd監(jiān)聽的fd的處理,當(dāng)然讀者可以直接跳過,在后面也跳過這些fd監(jiān)聽事件的處理,這并不會影響消息機制的源碼分析。

int addFd(int fd, int ident, int events, ALooper_callbackFunc callback, void* data);
int addFd(int fd, int ident, int events, const sp<LooperCallback>& callback, void* data);

fd表示要監(jiān)聽的描述符;ident表示要監(jiān)聽的事件的標(biāo)識,值必須>=0或者為ALOOPER_POLL_CALLBACK(-2);event表示要監(jiān)聽的事件;callback是事件發(fā)生時的回調(diào)函數(shù)。

下面是addFd函數(shù)的代碼。

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

    if (!callback.get()) {    
        if (! mAllowNonCallbacks) {     
            ALOGE("Invalid attempt to set NULL callback but not allowed for this looper.");
            return -1;         //callback為空且 mAllowNonCallbacks為false則直接返回-1,添加失敗
        }

        if (ident < 0) {
            ALOGE("Invalid attempt to set NULL callback with ident < 0.");
            return -1;
        }
    } else {
        ident = POLL_CALLBACK;
    }

    { // 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);   //初始化epoll_event

        ssize_t requestIndex = mRequests.indexOfKey(fd);   //檢查需要監(jiān)聽的fd是否已經(jīng)存在
        if (requestIndex < 0) {
            //注冊需要監(jiān)聽的fd
            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;
            }
  //將封裝的request保存到mRequests(KeyedVector對象,類似于Map)中,key為監(jiān)聽的文件描述符
            mRequests.add(fd, request);
        } else {
            int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_MOD, fd, & eventItem);
            if (epollResult < 0) {
                if (errno == ENOENT) {     //舊的文件描述符可以已經(jīng)關(guān)閉,需要重新添加注冊監(jiān)聽
                    // Tolerate ENOENT because it means that an older file descriptor was
                    // closed before its callback was unregistered and meanwhile a new
                    // file descriptor with the same number has been created and is now
                    // being registered for the first time.  This error may occur naturally
                    // when a callback has the side-effect of closing the file descriptor
                    // before returning and unregistering itself.  Callback sequence number
                    // checks further ensure that the race is benign.
                    //
                    // Unfortunately due to kernel limitations we need to rebuild the epoll
                    // set from scratch because it may contain an old file handle that we are
                    // now unable to remove since its file descriptor is no longer valid.
                    // No such problem would have occurred if we were using the poll system
                    // call instead, but that approach carries others disadvantages.
#if DEBUG_CALLBACKS
                    ALOGD("%p ~ addFd - EPOLL_CTL_MOD failed due to file descriptor "
                            "being recycled, falling back on EPOLL_CTL_ADD: %s",
                            this, strerror(errno));
#endif
                    epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, & eventItem); //重新添加注冊監(jiān)聽
                    if (epollResult < 0) {
                        ALOGE("Error modifying or adding epoll events for fd %d: %s",
                                fd, strerror(errno));
                        return -1;   //添加失敗返回-1
                    }
                    scheduleEpollRebuildLocked();   //重新創(chuàng)建epoll
                } else {
                    ALOGE("Error modifying epoll events for fd %d: %s", fd, strerror(errno));
                    return -1;
                }
            }
            mRequests.replaceValueAt(requestIndex, request);    //替換成新的Request
        }
    } // release lock
    return 1;
}

可以看到mAllowNonCallbacks的作用就在于此,當(dāng)mAllowNonCallbacks為true時允許callback為NULL,在pollOnce中ident作為結(jié)果返回,否則不允許callback為空,當(dāng)callback不為NULL時,ident的值會被忽略。

由于一開始初始化的時候mAllowNonCallbacks設(shè)置為false,如果callback為空則添加失敗,添加成功的ident都為POLL_CALLBACK,這在接下來對這些fd的監(jiān)聽處理至關(guān)重要。

接著addFd函數(shù)中將監(jiān)聽的fd、event、indent等封裝在一個Request對象中,然后根據(jù)fd從 mRequests(KeyedVector對象,類似于Map)查找監(jiān)聽的fd是否已經(jīng)存在,如果不存在則通過epoll_ctl注冊監(jiān)聽(EPOLL_CTL_ADD)并將該Request對象存儲在 mRequests對象中,如果存在則通過epoll_ctl修改監(jiān)聽(EPOLL_CTL_MOD)并通過mRequests.replaceValueAt替換成最新的Request對象。

二、消息的發(fā)送

在java層中發(fā)送消息的接口有很多個,但最終都會調(diào)用到MessageQueue.enqueueMessage函數(shù)。

    boolean enqueueMessage(Message msg, long when) {
        if (msg.target == null) {
            throw new IllegalArgumentException("Message must have a target.");
        }
        if (msg.isInUse()) {
            throw new IllegalStateException(msg + " This message is already in use.");
        }

        synchronized (this) {
            if (mQuitting) {
                IllegalStateException e = new IllegalStateException(
                        msg.target + " sending message to a Handler on a dead thread");
                Log.w(TAG, e.getMessage(), e);
                msg.recycle();
                return false;
            }

            msg.markInUse();
            msg.when = when;
            Message p = mMessages;
            boolean needWake;
            //如果p為空即消息隊列為空,或者新添加的消息的執(zhí)行時間when是0,
            //或者新添加的消息的執(zhí)行時間比消息隊列頭的消息的執(zhí)行時間還早說明消息隊列中沒有消息,
            //那么msg將是第一個消息,needWake根據(jù)mBlocked的情況考慮是否觸發(fā)
            if (p == null || when == 0 || when < p.when) {
                // New head, wake up the event queue if blocked.
                msg.next = p;
                mMessages = msg;
                needWake = mBlocked;    //當(dāng)前消息隊列阻塞則需要喚醒
            } else {
                //否則根據(jù)when將該消息插入到適合的位置
               //當(dāng)前消息隊列頭部消息為攔截器則不需要喚醒
                needWake = mBlocked && p.target == null && msg.isAsynchronous(); 
                Message prev;
                for (;;) {
                    prev = p;
                    p = p.next;
                    if (p == null || when < p.when) {
                        break;
                    }
                    if (needWake && p.isAsynchronous()) {
                        needWake = false;           //當(dāng)前消息為異步消息則不需要喚醒
                    }
                }
                msg.next = p; // invariant: p == prev.next
                prev.next = msg;
            }

            //調(diào)用nativeWake,以觸發(fā)nativePollOnce函數(shù)結(jié)束等待
            if (needWake) {
                nativeWake(mPtr);
            }
        }
        return true;
    }

可以看到發(fā)送消息是根據(jù)當(dāng)前消息隊列的情況和該消息的執(zhí)行時間(when)去插入到隊列中合適的位置,有三種情況該消息將插入到隊列頭部,一是消息隊列沒有消息,二是該消息執(zhí)行時間(when)為0,三是該消息的執(zhí)行時間比該消息隊列第一個消息的執(zhí)行時間還要早;其他情況則是根據(jù)執(zhí)行時間(when)將該消息插入到合適的位置。這樣消息的發(fā)送就成功了。

再看一下nativeWake觸發(fā)nativePollOnce函數(shù)結(jié)束等待的條件,一般來說當(dāng)前消息隊列正處于blocked(阻塞狀態(tài))且該消息執(zhí)行時間(when)為0則需要喚醒正在等待的epoll對象。

接著看nativeWake的C++代碼:

//android_os_MessageQueue.cpp
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();
}

//Looper.cpp
void Looper::wake() {
#if DEBUG_POLL_AND_WAKE
    ALOGD("%p ~ wake", this);
#endif

    uint64_t inc = 1;
    //向eventFd寫入一個uint64_t大小的數(shù)據(jù)以喚醒epoll
    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: %s", strerror(errno));
        }
    }
}

void Looper::awoken() {
#if DEBUG_POLL_AND_WAKE
    ALOGD("%p ~ awoken", this);
#endif

    uint64_t counter;
    //讀取一個uint64_t的數(shù)據(jù)
    TEMP_FAILURE_RETRY(read(mWakeEventFd, &counter, sizeof(uint64_t)));
}

可以看到nativeWake最終調(diào)用到native層Looper的wake函數(shù),在wake函數(shù)中向eventFd寫入一個uint64_t大小的數(shù)據(jù),這樣由于eventFd有數(shù)據(jù)可讀因此epoll_wait會從等待狀態(tài)中醒來。eventFd的讀數(shù)據(jù)是在awoken函數(shù),awoken是在epoll_wait結(jié)束等待后被調(diào)用到,只是將數(shù)據(jù)讀出后將可以繼續(xù)往后處理了,至于awoken在哪里調(diào)用到在后面會說到。

Java層不止可以發(fā)送消息,native層也可以發(fā)送消息,native層發(fā)送消息是在Looper的sendMessageAtTime函數(shù)里面。

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

        //根據(jù)執(zhí)行時間uptine進(jìn)行排隊
        size_t messageCount = mMessageEnvelopes.size();
        while (i < messageCount && uptime >= mMessageEnvelopes.itemAt(i).uptime) {
            i += 1;
        }

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

        // Optimization: If the Looper is currently sending a message, then we can skip
        // the call to wake() because the next thing the Looper will do after processing
        // messages is to decide when the next wakeup time should be.  In fact, it does
        // not even matter whether this code is running on the Looper thread.
        if (mSendingMessage) {
            return;
        }
    } // release lock

    // 如果當(dāng)前消息插入到頭部則喚醒epoll_wait
    if (i == 0) {
        wake();
    }
}

可以看到在native層的消息是用MessageEnvelope封裝了該消息Message以及處理這個消息的Handler和執(zhí)行時間uptime,然后根據(jù)執(zhí)行時間進(jìn)行排隊,如果該消息是排在隊列的最前面則需要通過調(diào)用wake函數(shù)喚醒epoll_wait。可以看出native層發(fā)送消息的流程跟Java層發(fā)送消息的流程很相似。

根據(jù)上面Java層和native層發(fā)送消息的分析,可以看到兩者發(fā)送消息時都是根據(jù)消息的執(zhí)行時間(when和uptime)進(jìn)行排隊,然后再判斷是否需要喚醒正在等待epoll_wait從而處理剛插入的消息,喚醒的步驟是往epoll監(jiān)聽的mWakeEventFd文件描述符寫入數(shù)據(jù)。

三、消息循環(huán)和處理

消息的循環(huán)和處理是在Java層的Looper.loop()進(jìn)行,接下來就開始分析這一個函數(shù)。

    public static void loop() {
        final Looper me = myLooper();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        final MessageQueue queue = me.mQueue;

        // Make sure the identity of this thread is that of the local process,
        // and keep track of what that identity token actually is.
        Binder.clearCallingIdentity();
        final long ident = Binder.clearCallingIdentity();

        for (;;) {
            Message msg = queue.next(); // 獲取下一個消息,可能會阻塞
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }

            // This must be in a local variable, in case a UI event sets the logger
            Printer logging = me.mLogging;
            if (logging != null) {
                logging.println(">>>>> Dispatching to " + msg.target + " " +
                        msg.callback + ": " + msg.what);
            }

            //調(diào)用處理這一個Message的Handler處理這一個消息
            msg.target.dispatchMessage(msg);

            if (logging != null) {
                logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
            }

            // Make sure that during the course of dispatching the
            // identity of the thread wasn't corrupted.
            final long newIdent = Binder.clearCallingIdentity();
            if (ident != newIdent) {
                Log.wtf(TAG, "Thread identity changed from 0x"
                        + Long.toHexString(ident) + " to 0x"
                        + Long.toHexString(newIdent) + " while dispatching to "
                        + msg.target.getClass().getName() + " "
                        + msg.callback + " what=" + msg.what);
            }

//當(dāng)消息處理完畢需要進(jìn)行回收,這是因為消息隊列是以鏈表的形式存在,因此不回收占用內(nèi)存會一直增加
            msg.recycleUnchecked();
        }
    }

loop函數(shù)是一個死循環(huán),每次從 queue.next()獲取下一個需要處理的消息,然后通過msg.target.dispatchMessage(msg)調(diào)用這一個消息的Handler處理這一個消息,處理完畢需要對這一個消息進(jìn)行回收。調(diào)用queue.next()的時候可能會阻塞是因為最終是調(diào)用到epoll_wait進(jìn)行監(jiān)聽等待。

接下來看MessageQueue.next()函數(shù)。

    Message next() {
        // Return here if the message loop has already quit and been disposed.
        // This can happen if the application tries to restart a looper after quit
        // which is not supported.
        final long ptr = mPtr;
        if (ptr == 0) {
            return null;
        }

        int pendingIdleHandlerCount = -1; // -1 only during first iteration
        int nextPollTimeoutMillis = 0;
        for (;;) {
            if (nextPollTimeoutMillis != 0) {
                Binder.flushPendingCommands();
            }

            //調(diào)用nativePollOnce等待nextPollTimeoutMillis,在這里可能會阻塞
            nativePollOnce(ptr, nextPollTimeoutMillis);

            synchronized (this) {
                // Try to retrieve the next message.  Return if found.
                final long now = SystemClock.uptimeMillis();
                Message prevMsg = null;
                Message msg = mMessages;
                //如果第一個Message為Barrier則往后找到第一個異步消息
                if (msg != null && msg.target == null) {
                    // Stalled by a barrier.  Find the next asynchronous message in the queue.
                    do {
                        prevMsg = msg;
                        msg = msg.next;
                    } while (msg != null && !msg.isAsynchronous());
                }
                if (msg != null) {
                    if (now < msg.when) {
                        // Next message is not ready.  Set a timeout to wake up when it is ready.
                        //下一個消息還沒有到執(zhí)行時間,設(shè)置下一個消息的超時
                        //這一個時間也是下一個循環(huán)nativePollOnce需要等待的時間
                        nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                    } else {
                        // Got a message.
                        mBlocked = false;
                        if (prevMsg != null) {
                            prevMsg.next = msg.next;
                        } else {
                            mMessages = msg.next;
                        }
                        msg.next = null;
                        if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                        msg.markInUse();
                        return msg;       //返回一個Message給Looper進(jìn)行處理
                    }
                } else {
                    // No more messages.
                    nextPollTimeoutMillis = -1;
                }

                // Process the quit message now that all pending messages have been handled.
                if (mQuitting) {
                    dispose();
                    return null;
                }

                // 處理注冊的Idlehandler,當(dāng)沒有消息時,Looper會調(diào)用Idlehandler做一些工作比如垃圾回收
                if (pendingIdleHandlerCount < 0
                        && (mMessages == null || now < mMessages.when)) {
                    pendingIdleHandlerCount = mIdleHandlers.size();
                }
                if (pendingIdleHandlerCount <= 0) {
                    // No idle handlers to run.  Loop and wait some more.
                    //沒有Idlehandler執(zhí)行則需要進(jìn)行等待,mBlocked設(shè)置為true,然后調(diào)用continue繼續(xù)下一個循環(huán)
                    mBlocked = true;
                    continue;
                }

                if (mPendingIdleHandlers == null) {
                    mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
                }
                mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
            }

            // Run the idle handlers.
            // We only ever reach this code block during the first iteration.
            for (int i = 0; i < pendingIdleHandlerCount; i++) {
                final IdleHandler idler = mPendingIdleHandlers[i];
                mPendingIdleHandlers[i] = null; // release the reference to the handler

                boolean keep = false;
                try {
                    keep = idler.queueIdle();
                } catch (Throwable t) {
                    Log.wtf(TAG, "IdleHandler threw exception", t);
                }

                if (!keep) {
                    synchronized (this) {
                        mIdleHandlers.remove(idler);
                    }
                }
            }

            // Reset the idle handler count to 0 so we do not run them again.
            pendingIdleHandlerCount = 0;

            // While calling an idle handler, a new message could have been delivered
            // so go back and look again for a pending message without waiting.
            nextPollTimeoutMillis = 0;     //設(shè)置nextPollTimeoutMillis為0
        }
    }

nativePollOnce進(jìn)入native層后會根據(jù)native層的消息隊列和nextPollTimeoutMillis決定是否調(diào)用epoll_wait進(jìn)入等待狀態(tài),這個在接下來會講到。

nativePollOnce返回后會取Java層消息隊列的頭部消息,如果頭部消息是Barrier(即target == null的消息)就往后遍歷到第一個異步消息。如果沒有需要執(zhí)行的消息。則設(shè)置nextPollTimeoutMillis = -1,否則根據(jù)這一個消息的執(zhí)行時間(when),如果已經(jīng)到執(zhí)行時間則將將該消息markInUse并從消息隊列移除最后返回,否則設(shè)置nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE)為這一個消息距離需要執(zhí)行還要多久。

在next函數(shù)有兩個變量需要關(guān)注,一個是nextPollTimeoutMillis,另一個是mBlocked。
nextPollTimeoutMillis是nativePollOnce需要傳入的參數(shù),-1表示沒有需要處理的消息,大于等于0則表示java層下一個消息需要多久執(zhí)行。
mBlocked是表示當(dāng)前是否處于阻塞狀態(tài),可以看到當(dāng)有消息需要立即處理時會被設(shè)置為false,當(dāng)沒有消息或者消息還未到執(zhí)行時間而且當(dāng)前需要處理的Idlehandler數(shù)目為0時設(shè)置為true。

接下來看nativePollOnce函數(shù)。

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

void NativeMessageQueue::pollOnce(JNIEnv* env, jobject pollObj, int timeoutMillis) {
    mPollEnv = env;
    mPollObj = pollObj;
    mLooper->pollOnce(timeoutMillis);
    mPollObj = NULL;
    mPollEnv = NULL;

    if (mExceptionObj) {
        env->Throw(mExceptionObj);
        env->DeleteLocalRef(mExceptionObj);
        mExceptionObj = NULL;
    }
}

inline int pollOnce(int timeoutMillis) {
        return pollOnce(timeoutMillis, NULL, NULL, NULL);
}


int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
    int result = 0;
    for (;;) {          //進(jìn)入死循環(huán),當(dāng)調(diào)用過一次pollInner后就會跳出
        while (mResponseIndex < mResponses.size()) {
            const Response& response = mResponses.itemAt(mResponseIndex++);
            int ident = response.request.ident;
            //根據(jù)上面分析這里ident都會為POLL_CALLBACK(-2),因此這里不會執(zhí)行
            if (ident >= 0) {
                int fd = response.request.fd;
                int events = response.events;
                void* data = response.request.data;
#if DEBUG_POLL_AND_WAKE
                ALOGD("%p ~ pollOnce - returning signalled identifier %d: "
                        "fd=%d, events=0x%x, data=%p",
                        this, ident, fd, events, data);
#endif
                if (outFd != NULL) *outFd = fd;
                if (outEvents != NULL) *outEvents = events;
                if (outData != NULL) *outData = data;
                return ident;
            }
        }

        if (result != 0) {    //第二次循環(huán)后會進(jìn)入并返回,結(jié)束循環(huán)
#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;
        }

       //調(diào)用pollInner函數(shù)
        result = pollInner(timeoutMillis);
    }
}

可以看到nativePollOnce最終調(diào)用到了 Looper::pollOnce函數(shù),Looper::pollOnce函數(shù)最后調(diào)用到了pollInner函數(shù)。

int Looper::pollInner(int timeoutMillis) {
#if DEBUG_POLL_AND_WAKE
    ALOGD("%p ~ pollOnce - waiting: timeoutMillis=%d", this, timeoutMillis);
#endif

    //取native層和Java層下一個最早需要執(zhí)行的消息作為epoll等待的時間
    if (timeoutMillis != 0 && mNextMessageUptime != LLONG_MAX) {
        nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
        //計算nativce層下一個消息還有多久執(zhí)行
        int messageTimeoutMillis = toMillisecondTimeoutDelay(now, mNextMessageUptime);
       //當(dāng)messageTimeoutMillis大于0且java層沒有消息,或者native層messageTimeoutMillis小于Java層的timeoutMillis時
        if (messageTimeoutMillis >= 0
                && (timeoutMillis < 0 || messageTimeoutMillis < timeoutMillis)) {
            timeoutMillis = messageTimeoutMillis;
        }
#if DEBUG_POLL_AND_WAKE
        ALOGD("%p ~ pollOnce - next message in %" PRId64 "ns, adjusted timeout: timeoutMillis=%d",
                this, mNextMessageUptime - now, timeoutMillis);
#endif
    }

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

    // We are about to idle.
    mPolling = true;

    //epoll開始等待監(jiān)聽事件的發(fā)生
    struct epoll_event eventItems[EPOLL_MAX_EVENTS];
    int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);

    // No longer idling.
    mPolling = false;

    // Acquire lock.
    mLock.lock();

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

    // 事件總數(shù)小于0說明發(fā)送錯誤
    if (eventCount < 0) {
        if (errno == EINTR) {
            goto Done;
        }
        ALOGW("Poll failed with an unexpected error: %s", strerror(errno));
        result = POLL_ERROR;    //POLL_ERROR = -4
        goto Done;
    }

    // 事件總數(shù)為0說明超時
    if (eventCount == 0) {
#if DEBUG_POLL_AND_WAKE
        ALOGD("%p ~ pollOnce - timeout", this);
#endif
        result = POLL_TIMEOUT;    //POLL_TIMEOUT = -3
        goto Done;
    }

    // 事件總數(shù)大于0則讀取
#if DEBUG_POLL_AND_WAKE
    ALOGD("%p ~ pollOnce - handling events from %d fds", this, eventCount);
#endif

    for (int i = 0; i < eventCount; i++) {
        int fd = eventItems[i].data.fd;
        uint32_t epollEvents = eventItems[i].events;
        if (fd == mWakeEventFd) {         //有新消息添加進(jìn)入
            if (epollEvents & EPOLLIN) {
                awoken();      //調(diào)用awoken讀取數(shù)據(jù)
            } else {
                ALOGW("Ignoring unexpected epoll events 0x%x on wake event fd.", epollEvents);
            }
        } else {           //處理其他監(jiān)聽的fd的事件
            ssize_t requestIndex = mRequests.indexOfKey(fd);    //根據(jù)fd從mRequests中查找發(fā)生IO事件需要處理的Request對象
            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));   //將需要處理的Request對象push到mResponses(Vector對象中)
            } else {
                ALOGW("Ignoring unexpected epoll events 0x%x on fd %d that is "
                        "no longer registered.", epollEvents, fd);
            }
        }
    }
Done: ;

    // Invoke pending message callbacks.
    mNextMessageUptime = LLONG_MAX;
    while (mMessageEnvelopes.size() != 0) {
        nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
       //獲取native層的頭部消息,如果可以執(zhí)行則調(diào)用相應(yīng)的Handler執(zhí)行
        const MessageEnvelope& messageEnvelope = mMessageEnvelopes.itemAt(0);
        if (messageEnvelope.uptime <= now) {
            // Remove the envelope from the list.
            // We keep a strong reference to the handler until the call to handleMessage
            // finishes.  Then we drop it so that the handler can be deleted *before*
            // we reacquire our lock.
            { // obtain handler
                sp<MessageHandler> handler = messageEnvelope.handler;
                Message message = messageEnvelope.message;
                mMessageEnvelopes.removeAt(0);
                mSendingMessage = true;
                mLock.unlock();

#if DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKS
                ALOGD("%p ~ pollOnce - sending message: handler=%p, what=%d",
                        this, handler.get(), message.what);
#endif
                handler->handleMessage(message);     //處理native層的Message
            } // 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;    //記錄下一個Message發(fā)生的時間
            break;
        }
    }

    // Release lock.
    mLock.unlock();

    //處理所有發(fā)生IO事件的fd,通過調(diào)用callback進(jìn)行回調(diào)處理
    // Invoke all response callbacks.
    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;
#if DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKS
            ALOGD("%p ~ pollOnce - invoking fd event callback %p: fd=%d, events=0x%x, data=%p",
                    this, response.request.callback.get(), fd, events, data);
#endif
            // Invoke the callback.  Note that the file descriptor may be closed by
            // the callback (and potentially even reused) before the function returns so
            // we need to be a little careful when removing the file descriptor afterwards.
            int callbackResult = response.request.callback->handleEvent(fd, events, data);    //回調(diào)處理
            if (callbackResult == 0) {
                removeFd(fd, response.request.seq);  //移除
            }

            // Clear the callback reference in the response structure promptly because we
            // will not clear the response vector itself until the next poll.
            response.request.callback.clear();            //移除回調(diào)函數(shù)
            result = POLL_CALLBACK;     //POLL_CALLBACK = -2
        }
    }
    return result;
}

在上面的分析我們知道Java層的消息都保存在了Java層MessageQueue的成員mMessages中,Native層的消息都保存在了Native Looper的mMessageEnvelopes中,這說明了有兩個按時間排序的消息隊列。timeoutMillis表示Java層下一個消息還有多久需要執(zhí)行,mNextMessageUpdate表示Native層下一個要執(zhí)行的消息的時間。當(dāng)timeoutMillis為0,epoll_wait直接設(shè)置TimeOut為0;如果timeoutMillis為-1(說明Java層無消息)則計算native層下一個需要mNextMessageUpdate獲取native層的timeout作為epoll_wait的timeout參數(shù)。

epoll_wait返回的是所監(jiān)聽文件描述符發(fā)生IO事件的總數(shù)(eventCount),一般有三種情況:

  • eventCount < 0 : 出錯返回
  • eventCount = 0:超時,監(jiān)聽的文件描述符沒有事件發(fā)送
  • eventCount > 0 : 監(jiān)聽的文件描述符有時間發(fā)生

前兩種情況都是通過goto Done直接跳到Done后面的代碼。第三種情況則會循環(huán)處理所有的事件,如果是mWakeReadPipeFd的EPOLLIN事件就調(diào)用awoken函數(shù)(上面所說的awoken函數(shù)就是在這里執(zhí)行),如果不是則是通過addFD添加的文件描述符(fd)發(fā)送了IO事件,此時將發(fā)生的事件封裝成Response再push到mResonses隊列(Vector對象)。

接著再看一下Done部分的代碼,一開始從mMessageEnvelopes取出頭部的Native消息,如果到達(dá)了執(zhí)行時間就調(diào)用它內(nèi)部保存的MessageeHandler的handleMessage處理并從Native消息隊列移除,設(shè)置result為POLL_CALLBACK,否則計算mNextMessageUptime表示Native消息隊列下一次消息要執(zhí)行的時間。

最后,遍歷mResponses(前面剛通過pushResponse存進(jìn)去的),如果response.request.ident == POLL_CALLBACK,就調(diào)用注冊的callback的handleEvent(fd, events, data)進(jìn)行處理,然后從mResonses隊列中移除,這次遍歷完之后,mResponses中保留來來的就都是ident>=0并且callback為NULL的了。由于在NativeMessageQueue初始化Looper時傳入了mAllowNonCallbacks為false,所以這次處理完后mResponses一定為空。

接下來返回到pollOnce。pollOnce是一個for循環(huán),pollInner中處理了所有response.request.ident==POLL_CALLBACK的Response,在第二次進(jìn)入for循環(huán)后如果mResponses不為空就可以找到ident>0的Response,將其ident作為返回值返回由調(diào)用pollOnce的函數(shù)自己處理,在這里我們是在NativeMessageQueue中調(diào)用的Loope的pollOnce,沒對返回值進(jìn)行處理,而且mAllowNonCallbacks為false也就不可能進(jìn)入這個循環(huán)。pollInner返回值不可能是0,或者說只可能是負(fù)數(shù),所以pollOnce中的for循環(huán)只會執(zhí)行兩次,在第二次就返回了。

四、總結(jié)

這篇源碼分析涉及到很多l(xiāng)inux的知識,如果沒有l(wèi)inux基礎(chǔ)看起來會很費勁。從這篇文章我們可以看到很清楚地看到Android是如何利用linux內(nèi)核去構(gòu)建自己的framework層的,這對學(xué)習(xí)Android底層會有很大的幫助。

參考資料

  1. IO多路復(fù)用之epoll總結(jié)
  2. TLS--線程局部存儲
  3. linux eventfd
  4. Android消息處理機制(Handler、Looper、MessageQueue與Message)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容