Handler

作者: 冉桓彬 | 来源:发表于2017-05-01 11:56 被阅读142次

    1、有几个问题:

    1. Handler与线程的关系;
    2. Handler、Looper、MessageQueue的关系;
    3. Android中为什么主线程不会因为Looper.loop()里的死循环卡死? 
    4. 没看见哪里有相关代码为这个死循环准备了一个新线程去运转? 
    5. Activity的生命周期这些方法这些都是在主线程里执行的吧,那这些生命周期方法是怎么实现在死循环体外能够执行起来的?
    

    一、关于Looper :

    1.1 ActivityThread.main:
    public final class ActivityThread {
        static Handler sMainThreadHandler;
        /**
         * ActivityThread.main是主程序的入口, 在这里进行Looper与Message的初始化操作;
         */
        public static void main(String[] args) {
            Looper.prepareMainLooper();      模块<1.2>
            if (sMainThreadHandler == null) {
                sMainThreadHandler = thread.getHandler();
            }
            Looper.loop();
        }
    }
    

    1.2 Looper.prepareMainLooper() :

    public final class Looper {
        public static void prepareMainLooper() {
            /**
             * 对Looper进行初始化;
             */
            prepare(false);
            synchronized (Looper.class) {
                /**
                 * 1. 如果Looper为null, 则对Looper进行初始化, 如果不为空, 则抛出异常;
                 * 2. 换句话说也就是一个线程只允许一个Looper存在;
                 */
                if (sMainLooper != null) {
                    throw new IllegalStateException("The main Looper has already been prepared.");
                }
                sMainLooper = myLooper();        模块<1.3>
            }
        }
    
        private static void prepare(boolean quitAllowed) {
            /**
             * 一个线程对应一个Looper, Thread与Looper是一对一关系;
             */
            if (sThreadLocal.get() != null) {
                throw new RuntimeException("Only one Looper may be created per thread");
            }
            /**
             * 如果Looper不存在, 则对Looper进行初始化, 并且利用ThreadLocal将Looper与Thread进行绑定;
             */
            sThreadLocal.set(new Looper(quitAllowed));
        }
    
        public static void prepare() {
            prepare(true);
        }
        final MessageQueue mQueue;
        /**
         * 一个线程只能有一个Looper, 而在初始化Looper时才会进行MessageQueue的初始化, 
         * 所以线程, Looper, MessageQueue的关系1:1:1;
         */
        private Looper(boolean quitAllowed) {
            mQueue = new MessageQueue(quitAllowed);
            mThread = Thread.currentThread();
        }
    }
    
    • 结合上面代码可以看出, 一个线程有且只有一个Looper, 而MessageQueue又是在初始化Looper才进行的初始化, 所以线程, Looper, MessageQueue的关系是1:1:1;

    二、关于MessageQueue:

    2.1 MessageQueue构造函数 :
    public final class MessageQueue {
        private native static long nativeInit();
        private long mPtr;
    
        MessageQueue(boolean quitAllowed) {
            mQuitAllowed = quitAllowed;
            /**
             * 触发native层方法, 获取native层的NativeMessageQueue的引用, 使其指向mPtr;
             */
            mPtr = nativeInit();   模块<2.2>
        }
    }
    

    http://androidxref.com/7.1.1_r6/xref/frameworks/base/core/jni/android_os_MessageQueue.cpp;

    2.2 MessageQueue.nativeInit:

    static jlong android_os_MessageQueue_nativeInit(JNIEnv* env, jclass clazz) {
        NativeMessageQueue* nativeMessageQueue = new NativeMessageQueue();    模块<2.3>
        nativeMessageQueue->incStrong(env);
        return reinterpret_cast<jlong>(nativeMessageQueue);
    }
    
    • 在java层进行MessageQueue的初始化的时候, 在native层也会创建一个NativeMessageQueue对象, 并且将该对象的引用返回给java层的MessageQueue的mPtr对象, 这样java层的MessageQueue与Native的NativeMessageQueue之间就产生了关联;

    2.3 NativeMessageQueue构造函数 :

    NativeMessageQueue::NativeMessageQueue() :
            mPollEnv(NULL), mPollObj(NULL), mExceptionObj(NULL) {
        mLooper = Looper::getForThread();
        if (mLooper == NULL) {
            mLooper = new Looper(false);   模块<2.4>
            Looper::setForThread(mLooper);
        }
    }
    
    • native层的NativeMessageQueue在初始化的时候也会初始化一个Native层的Looper, native层NativeMessageQueue和Looper也是一一对应的关系;

    2.4 Looper.looper() :

    在读下面代码之前, 先复制一段IO多路复用_epoll的文章, 文章最后复制了一段epoll的概念

    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);
        AutoMutex _l(mLock);
        rebuildEpollLocked();
    }
    
    void Looper::rebuildEpollLocked() {
        // Close old epoll instance if we have one.
        /**
         * 由最下面的多路复用_epoll的介绍可知, 当我们在使用完一个句柄之后需要close它, 这里mEpollFd为该句柄的引用, 
         * 如果地址值 > 0, 说明前面已经创建过mEpollFd;
         */
        if (mEpollFd >= 0) {
            close(mEpollFd);
        }
        /**
         * static const int EPOLL_SIZE_HINT = 8; 创建一个epoll句柄, 并且该句柄监听的size为32个字节;
         */
        mEpollFd = epoll_create(EPOLL_SIZE_HINT);
    
        struct epoll_event eventItem;
        memset(& eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union
        eventItem.events = EPOLLIN;
        eventItem.data.fd = mWakeEventFd;
        /**
         * 1. 注册新的mWakeEventFd到mEpollFd中去;
         * 2. 对应的文件描述符可以读;
         */
        int result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeEventFd, & eventItem);
        for (size_t i = 0; i < mRequests.size(); i++) {...}
    }
    

    三、Looper与MessageQueue关联:

    3.1 Looper.loop() :
    public final class Looper {
        public static void loop() {
            final Looper me = myLooper();
            /**
             * 1. 在使用Looper之前一定要通过prepare()对Looper进行初始化;
             * 2. 而且一个线程只能初始化一次Looper;
             */
           if (me == null) {
                throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
            }
            final MessageQueue queue = me.mQueue;
            Binder.clearCallingIdentity();
            final long ident = Binder.clearCallingIdentity();
            for (;;) {
                /**
                 * 如何获取Message?
                 */
                Message msg = queue.next();      模块<3.2>
                /**
                 * 如果msg == null, 直接退出该loop?  msg什么情况为null?
                 */
                if (msg == null) {
                    return;
                }
                /**
                 * 1. 结合模块<四>部分可知target指向Handler;\
                 * 2. 此时dispatchMessage的调用已经处于主线程中;
                 */
                msg.target.dispatchMessage(msg);    模块<4.7>
                final long newIdent = Binder.clearCallingIdentity();
                msg.recycleUnchecked();
            }
        }
        /**
         * 由下文Handler源码分析可知, 当我们以Handler.post形式向MessageQueue中添加消息时, 创建的Message会持有Runnable的引用, 
         * 如果以Handler.sendMessage的形式向MessageQueue中添加消息时, mCallback = null和msg.callback = null, 
         * 并且handleMessage(...)默认是空实现, 所以如果是sendMessage形式, 需要我们自己重写handleMessage方法;
         */
        public void dispatchMessage(Message msg) {
            if (msg.callback != null) {
                handleCallback(msg);
            } else {
                if (mCallback != null) {
                    if (mCallback.handleMessage(msg)) {
                        return;
                    }
                }
                handleMessage(msg);
            }
        }
        private static void handleCallback(Message message) {
            message.callback.run();
        }
        public void handleMessage(Message msg) {
        }
    }
    

      调用loop()之后, Looper轮训器进入循环状态, 当msg = null时跳出该循环;

    3.2 MessageQueue.next :
    public final class MessageQueue {
        private native void nativePollOnce(long ptr, int timeoutMillis);
        Message next() {
            int pendingIdleHandlerCount = -1;
            int nextPollTimeoutMillis = 0;
            for (;;) {
                /**
                 *  1. nextPollTimeoutMillis默认为0;
                 */
                nativePollOnce(ptr, nextPollTimeoutMillis);     模块<3.3>
                synchronized (this) {
                    final long now = SystemClock.uptimeMillis();
                    Message prevMsg = null;
                    Message msg = mMessages;
                    /**
                     *  Message内部是一个链表结构, 此时先考虑在主线程中创建Handler的情况, (由下文Handler.post()相关源码可知)
                     *  当调用handler.enqueueMessage(...)时, 会创建一个Message, 并且该Message会持有当前Handler的引用, 所以
                     *  直接跳过该if语句;
                     */
                    if (msg != null && msg.target == null) {
                        do {
                            prevMsg = msg;
                            msg = msg.next;
                        } while (msg != null && !msg.isAsynchronous());
                    }
                    /**  
                     * msg != null的条件是mMessages != null, 而mMessages != null的条件又是我们调用enqueueMessage()
                     * 方法对mMessages进行赋值, 我们先假设我们在调用Handler.enqueueMessage时都是按时间线性的顺序进行消息入队;
                     * 则会进入到else{...}语句中;
                     */
                    if (msg != null) {
                        if (now < msg.when) {
                            nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                        } else {
                            /**
                             * 由此可知当有消息到来时, mBlocked = false;
                             */
                            mBlocked = false;
                            /**
                             * 下面几行代码的意思就是获取Message链表的第一个元素Message, 然后删除掉该元素(FIFO);
                             */
                            if (prevMsg != null) {
                                prevMsg.next = msg.next;
                            } else {
                                mMessages = msg.next;
                            }
                            msg.next = null;
                            msg.markInUse();
                            return msg;
                        }
                    } else {
                        /**
                         * 当msg = null时, nextPollTimeoutMillis = -1, 继续向下;
                         */
                        nextPollTimeoutMillis = -1;
                    }
                    if (mQuitting) {...}
                    /**
                     * 当mMessages = null时, 进入第一个if语句pendingIdleHandlerCount = 0;
                     * 然后进入第二个if语句执行continue语句继续for循环, 并且调用nativePollOnce(), 此时nextPollTimeoutMillis = -1
                     */
                    if (pendingIdleHandlerCount < 0 && (mMessages == null || now < mMessages.when)) {
                        pendingIdleHandlerCount = mIdleHandlers.size();
                    }
                    if (pendingIdleHandlerCount <= 0) {
                        mBlocked = true;
                        continue;
                    }
                }
                for (int i = 0; i < pendingIdleHandlerCount; i++) {...}
                pendingIdleHandlerCount = 0;
                nextPollTimeoutMillis = 0;
            }
        }
    }
    

    上述next()代码很长, 大致逻辑如下:

    • 1、初始化变量nextPollTimeoutMillis = 0;
    • 2、MessageQueue内部维护了一个Message链表, 循环从链表中读取Message, 如果message == null, 则nextPollTimeoutMillis = -1, 如果存在继续向下执行 置nextPollTimeoutMillis = 0;
    • 3、然后调用nativePollOnce, 并传入对应的nextPollTimeoutMillis, 通过native层触发当前线程是否处于阻塞等待状态;
    3.3 MessageQueue.nativePollOnce:
    MessageQueue->nativePollOnce:
    static void android_os_MessageQueue_nativePollOnce(...jlong ptr, jint timeoutMillis) {
        NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
        /**
         * 结合模块<2.2>可知ptr指向NativeMessageQueue;
         */
        nativeMessageQueue->pollOnce(env, obj, timeoutMillis);
    }
    
    NativeMessageQueue->pollOnce():
    void NativeMessageQueue::pollOnce(JNIEnv* env, jobject pollObj, int timeoutMillis) {
        ...
        mLooper->pollOnce(timeoutMillis);   模块<3.4>
        ...
    }
    
    3.4 Looper.pollOnce:
    Looper->pollOnce(...):
    /**
     * timeoutMillis为我们在java中传入的nextPollTimeoutMillis变量;
     */
    int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
        int result = 0;
        for (;;) {
            while (mResponseIndex < mResponses.size()) {...}
            if (result != 0) {...}
            result = pollInner(timeoutMillis);
        }
    }
    
    int Looper::pollInner(int timeoutMillis) {
        /**
         * 只观察timeoutMillis引用的地方;
         * 由上文Native层的Looper初始化知道, mNextMessageUptime = LLONG_MAX;
         */
        if (timeoutMillis != 0 && mNextMessageUptime != LLONG_MAX) {...}
        int result = POLL_WAKE;
        mResponses.clear();
        mResponseIndex = 0;
        mPolling = true;
        /**
         * 1. 当timeoutMillis = -1时, 由epoll_wait定义可知该方法会一直阻塞;
         * 2. 如果timeoutMillis = 0继续向下执行, 并获取事件个数;
         */
        struct epoll_event eventItems[EPOLL_MAX_EVENTS];
        int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);   模块<3.5>
    
        // No longer idling.
        mPolling = false;
    
        // Acquire lock.
        mLock.lock();
    
        /**
         * 默认FALSE, 继续向下执行;
         */
        if (mEpollRebuildRequired) {...}
        /**
         * 当事件个数 ≤ 0 时执行Done: 部分的代码, 即异常情况, 此时先不考虑该情况;
         */
        if (eventCount < 0) {
            ...
            goto Done;
        }
        if (eventCount == 0) {
            ...
            goto Done;
        }
        /**
         * 当eventCount > 0 时, 遍历该eventItem, 并判断当前文件描述符是否为
         * mWakeEventFd, 如果是mWakeEventFd则调用awoken()唤醒, 否则则将该文件描述符
         * 添加到mResponses中去;
         */
        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 {
                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 {...}
            }
        }
    Done: ;
        ...
        return result;
    }
    
    void Looper::pushResponse(int events, const Request& request) {
        Response response;
        response.events = events;
        response.request = request;
        mResponses.push(response);
    }
    
    3.5 epoll_wait:
    int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout):
    
    • 等待事件的产生, 参数events用来从内核得到事件的集合, maxevents告诉内核这个events有多大, 参数timeout是超时时间(毫秒, 0会立即返回, -1将会阻塞). 该函数返回需要处理的事件数目, 如返回0表示已超时;

    四、关于Handler:

    4.1 Handler构造函数:
    public class Handler {
        public Handler() {
            this(null, false);
        }
        public Handler(Callback callback, boolean async) {
            /**
             * 1. 结合前文其实可知, Looper的获取使用了ThreadLocal, 也就是说一个线程只能有一个Looper;
             * 2. 但是Handler初始化时并没有做相关限制, 所以Handler与Looper的关系是多:1的关系;
             */
            mLooper = Looper.myLooper();
            if (mLooper == null) {
                throw new RuntimeException(
                    "Can't create handler inside thread that has not called Looper.prepare()");
            }
            mQueue = mLooper.mQueue;
        }
    }
    
    4.2 Handler.post :
    public class Handler {
        public final boolean post(Runnable r) {
            /**
             * 将Message发送至MessageQueue;
             */
            return  sendMessageDelayed(getPostMessage(r), 0);   模块<4.3>
        }
        private static Message getPostMessage(Runnable r) {
            /**
             *  初始化Message, 将r指向Message.callback;
             */
            Message m = Message.obtain();
            m.callback = r;
            return m;
        }
    }
    
    public final class Message {
        public static Message obtain() {
            ...
            return new Message();
        }
    }
    
    4.3 Handler.sendMessageDelayed :
    public class Handler {
        public final boolean sendMessageDelayed(Message msg, long delayMillis) {
            return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
        }
        public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
            MessageQueue queue = mQueue;
            return enqueueMessage(queue, msg, uptimeMillis);
        }
        private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
            msg.target = this;
            /**
             * msg进行入队操作;
             */
            return queue.enqueueMessage(msg, uptimeMillis);  模块<4.4>
        }
    }
    
    4.4 MessageQueue.enqueueMessage :
    public final class MessageQueue {
        boolean enqueueMessage(Message msg, long when) {
            ...
            synchronized (this) {
                msg.markInUse();
                msg.when = when;
                Message p = mMessages;
                boolean needWake;
                /**
                 * 1. 当第一次调用Handler.post时, 此时p = mMessage = null; 
                 * 2. 搜索上文可知loop.loop()时, 主线程会一直阻塞在nativePollOnce(...)处并且mBlocked = true;
                 * 3. 然后直接进入if (needWake) {...}内部;
                 */
                if (p == null || when == 0 || when < p.when) {
                    // New head, wake up the event queue if blocked.
                    msg.next = p;
                    mMessages = msg;
                    needWake = mBlocked;
                } else {
                    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;
                        }
                    }
                    msg.next = p; // invariant: p == prev.next
                    prev.next = msg;
                }
                /**
                 * 1. 能进入if语句内部的前提条件是needWake = true, 而needWake唯一被赋值就是needWake = mBlocked;
                 * 2. mBlocked只在MessageQueue.next()中被赋值.而结合上文又知道当没有消息被添加到MessageQueue队列中时, 
                 *    也就是Message链表为空时,  MessageQueue.next()会被一直阻塞在nativePollOnce(...), 而且mBlocked = true, 
                 *    当有消息被添加到消息队列时, 是一定会执行下面if(...)语句;
                 */
                if (needWake) {
                    /**
                     * 1. 通过模块<3.3>可知, 当没有消息时, 当前线程会在native层通过触发epoll_wait方法并传入
                     * -1将当前线程处于阻塞状态;
                     * 2. 然后在有消息到来时, 通过nativeWake方法欢喜线程;
                     */
                    nativeWake(mPtr);     模块<4.5>
                }
            }
            return true;
        }
        private native static void nativeWake(long ptr);
    }
    
    • 1、当没有消息到来时, MessageQueue.next()会被一直阻塞在nativePollOnce(...)处, 并且此时mBlock = true;
    • 2、当调用Handler.post或者Handler.sendMessage时, MessageQueue.enqueueMessage(...)会触发nativeWake(...)的执行;
    4.5 android_os_MessageQueue.nativeWake:
    MessageQueue --->
    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();      模块<4.6>
    }
    
    4.6 Looper.wake:
    Looper --->
    void Looper::wake() {
        uint64_t inc = 1;
        ssize_t nWrite = TEMP_FAILURE_RETRY(write(mWakeEventFd, &inc, sizeof(uint64_t)));
    }
    

      重点在这里的write(...)部分, 注意前文的epoll_wait(...)传入-1时会阻塞当前线程, 这里调用write(...)通过唤醒当前线程, pollOnce(...)会继续向下执行, 最终走到awoken方法;

    Looper.cpp --->
    void Looper::awoken() {
        uint64_t counter;
        TEMP_FAILURE_RETRY(read(mWakeEventFd, &counter, sizeof(uint64_t)));
    }
    

      从管道内读入数据, 即native层不会再阻塞在pollOnce(...), 所以java层的MessageQueue.next()也就不会再阻塞在nativePollOnce(ptr, nextPollTimeoutMillis)处, MessageQueue.next()继续向下执行由执行到了return msg处, 然后根据我们Handler.post还是Handler.sendMsg而选择是调用Handler.handlerCallback(...)还是Handler.handleMessage(...);

    4.7 Handler.dispatchMessage:
    /**
     * 1. post方式时callback == Runnable != null, 触发handlerCallback();
     * 2. sendMessage方式时callback == null, 触发handleMessage;
     */
    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }
    
    总结一下:

      1、关于IO多路复用, epoll以及pipe并不是很了解, 导致分析经常卡壳, 到现在也不能说清楚;

    多路复用_epoll:

    1、概念:
      epoll使用一个文件描述符管理多个描述符, 将用户关系的文件描述符的事件存放到内核的一个事件表中, 这样在用户空间和内核空间的copy只需要一次;
    2、epoll接口:

    #include <sys/epoll.h>
    int epoll_create(int size);
    int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
    int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);
    

    (1) int epoll_create(int size):
      创建一个epoll句柄, size用来告诉内核这个监听的数目一共有多大. 当创建好epoll句柄后, 它就是会占用一个fd值, 在使用完epoll之后, 必须调用close()关闭, 否则就可能导致fd被耗尽;

    (2) int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event):

      epoll的事件注册函数; 第一个参数是epoll_create()的返回值, 第二个参数表示动作, 用三个宏来表示:

    EPOLL_CTL_ADD: 注册新的fd到epfd中;
    EPOLL_CTL_MOD: 修改已经注册的fd的监听事件;
    EPOLL_CTL_DEL: 从epfd中删除一个fd;
    

    第三个参数是需要监听的fd, 第四个参数是告诉内核需要监听什么事件;

    struct epoll_event {
        __uint32_t events;  /* Epoll events */
        epoll_data_t data;  /* User data variable */
    };
    

    events可以是以下几个宏的集合:
    EPOLLIN :表示对应的文件描述符可以读(包括对端SOCKET正常关闭);
    EPOLLOUT:表示对应的文件描述符可以写;
    EPOLLPRI:表示对应的文件描述符有紧急的数据可读(这里应该表示有带外数据到来);
    EPOLLERR:表示对应的文件描述符发生错误;
    EPOLLHUP:表示对应的文件描述符被挂断;
    EPOLLET:将EPOLL设为边缘触发(Edge Triggered)模式,这是相对于水平触发(Level Triggered)来说的。
    EPOLLONESHOT:只监听一次事件,当监听完这次事件之后,如果还需要继续监听这个socket的话,需要再次把这个socket加入到EPOLL队列里

    (3) int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout):

      等待事件的产生, 参数events用来从内核得到事件的集合, maxevents告诉内核这个events有多大, 参数timeout是超时时间(毫秒, 0会立即返回, -1将会阻塞). 该函数返回需要处理的事件数目, 如返回0表示已超时;

    相关文章

      网友评论

          本文标题:Handler

          本文链接:https://www.haomeiwen.com/subject/namftxtx.html