Handler:从Java到native

本文详细介绍了Android系统中消息处理机制,包括Java层和Native层的Looper创建、Handler发送消息、MessageQueue的处理流程,以及如何停止Looper。重点讲解了Looper与线程的绑定、消息的分发和处理,以及文件描述符的监听。同时,探讨了Handler、Message、MessageQueue之间的交互,以及异步消息的处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Handler

Java层Looper对象绑定线程方法:在Java层,线程通过Looper.Prepare()方法创建looper对象,并将该对象存到线程局部空间中,下次访问时通过Looper.myLooper()获得该线程的Looper对象,其技术细节为Looper内有一个静态ThreadLocal类型遍历sThreadLocal,该变量任何线程都能访问,但是要做到不同线程通过它获取的值不一样的方法,就是线程关联的Java Thread对象内含有ThreadLocalMap的map,则可以将Looper内的静态成员sThreadLocal作为key,创建的Looper对象作为value存到该map中,这样不同的线程就可以访问Looper的sThreadLocal就可以在自己的ThreadLocalMap中得到对应的Looper对象。

Java层Looper结构:Looper对象含有MessageQueue的mQueues成员和其绑定的Thead类型mThead成员,MessageQueue中含有Message链表,mMessages成员总是指向下一个待处理消息mQueue。同时MessageQueue也是联系java层的Looper机制与native层的Looper机制的关键。MessageQueue的成员mPtr指向的为native层的NativeMessageQueue,当java层的MessageQueue创建的时候会创建native层的NativeMessageQueue,而native层looper机制的类结构和java层不一样,native 层的NativeMessageQueue含有Looper类型成员mLooper,所有功能都是mLooper完成,NativeMessageQueue只是作为与Java层沟通的桥梁。

Native层Looper对象绑定线程方法:native层Looper与线程的绑定是调用Linux函数实现的,实现思路与java层相似,也是通过一个pthread_key_t类型公共变量 gTLSKey,gTLSKey所有线程都能访问,通过pthread_setspecific 方法,以gTLSKey为key,新创建的Looper对象为Value存在线程的局部空间中,访问的时候通过pthread_getspecific (gTLSKey)获得该Looper对象。为了向开发者屏蔽调这些linux函数,安卓 native层使用Looper::setForThread(const sp& looper) 访问gTLSKey,并将其作为key,looper对象作为value存在线程局部空间中。通过Looper::getForThread访问该looper对象。

Native层Looper结构:NativeMessageQueue含有Looper类型成员mLooper,mLooper含有处理fd事件的mRequests成员、mResponses成员和处理Handler发来的消息的mMessageEnvelopes成员。

  1. mRequests是一个map,key为seq,Map为Request对象。seq为序列号,用来标识注册的fd。当在Looper中注册监听的fd时,通过向epoll_wait方法中填入待监听的fd和epoll_event。epoll_event的events成员指定了要监听fd的什么事件,这里一般是监听fd中有数据到来事件,而epoll_event的data成员是一个枚举类型,Looper中是指定其u64成员,存储Looper产生的序列号seq。当有事件到来时,该epoll_event结构体就会原封不动的返回。获得epoll_event后,通过读取data.u64字段就可以指定seq,

    struct epoll_event {
        __uint32_t events; /* 设置时表示事件掩码,指明了需要监听的事件种类
                               epoll返回时,表示获取到的事件*/
       epoll_data_t data; /* 使用者自定义的数据,当此事件发生时该数据将原封不动地返回给使用者 */
    };
    typedef union epoll_data {
        void*ptr;
        int fd;
       __uint32_t u32;
       __uint64_t u64;
    } epoll_data_t;
    

    那么我们怎么知道该事件是对应哪个fd呢?Looper在注册监听fd的时候会构建Request对象,Request对象中保存了fd、events、data、callback等值,这里的data一般填入的值就是上面所说的seq,

    struct Request {
          int fd;
          int ident;
          int events;
          sp<LooperCallback> callback;
          void* data;
    
          uint32_t getEpollEvents() const;
      };
    

    callback表示fd事件到来时的处理函数式接口。其只有handleEvent一个方法。

    /**
     * A looper callback.
     */
    class LooperCallback : public virtual RefBase {
    protected:
        virtual ~LooperCallback();
    
    public:
        /**
         * Handles a poll event for the given file descriptor.
         * It is given the file descriptor it is associated with,
         * a bitmask of the poll events that were triggered (typically EVENT_INPUT),
         * and the data pointer that was originally supplied.
         *
         * Implementations should return 1 to continue receiving callbacks, or 0
         * to have this file descriptor and callback unregistered from the looper.
         */
        virtual int handleEvent(int fd, int events, void* data) = 0;
    };
    

    而ident表示signal identifier,信号标识符。在我看来是用来表示事件的处理类型。当该fd的事件到来时,如果ident为POLL_CALLBACK(-2)则表示使用callback处理,否则ident的值一定大于0,表示将到来的fd事件返回给调用者(pollOnce),这个具体处理看下面。一个Request对象就表示一个注册的监听fd,Looper使用mRequests成员来存储这些Request对象。

    mResponses是一个Response对象集合。当fd事件来时,epoll_wait返回epoll_event结构,再从epoll_event结构的data.u64获得seq,通过seq便可以从mRequests获得对应的Request。然后将seq、events和Request包装成为一个Response对象。将其加入mResponses集合中。后序会遍历该集合,取出Response,通过其request成员的ident决定是调用request.callback处理,还是将还是将fd、events、seq返回给调用者(pollOnce的返回值)。

    mResponses在下一次pollOnce时处理ident大于0的情况,然后在后面的pollinner中清空mResponses。

    struct Response {
            SequenceNumber seq;
            int events;
            Request request;
        };
    using SequenceNumber = uint64_t;
    

    注册fd用Looper的addFd方法

  2. mMessageEnvelopes是一个MessageEnvelope类型的集合,集合中元素按照到来时间从小到大排列。MessageEnvelope中含有handler和message,native的handler是MessageHandler类型,不像在java层是Handler类型。在pollInner中当epoll_wait返回构建好了Response后第一个处理的就是mMessageEnvelopes,然后再是mResponses。遍历mMessageEnvelopes,取出MessageEnvelop然后获得

    struct MessageEnvelope {
            MessageEnvelope() : uptime(0) { }
    
            MessageEnvelope(nsecs_t u, sp<MessageHandler> h, const Message& m)
                : uptime(u), handler(std::move(h)), message(m) {}
    
            nsecs_t uptime; //发送时间,uptime clock
            sp<MessageHandler> handler;
            Message message;
        };
    

    法消息为sendMessage

循环过程:Java层Looper创建后调用它的loop()方法开启消息循环,looper()方法

  looper(){
....
 final Looper me = myLooper();
 me.mInLoop = true;
 final long ident = Binder.clearCallingIdentity();
    for (;;) {
              //死循环,除非调用了quit方法
            if (!loopOnce(me, ident, thresholdOverride)) {
                return;
            }
        }
}

loopOnce返回true表示还想要循环,否则退出循环,当调用Looper的quit方法时,就会导致loopOnce返回True并退出循环。

  * Poll and deliver single message, return true if the outer loop should continue.
     */
    @SuppressWarnings("AndroidFrameworkBinderIdentity")
    private static boolean loopOnce(final Looper me,
            final long ident, final int thresholdOverride) {

        Message msg = me.mQueue.next(); // might block
          ……

        try {
            msg.target.dispatchMessage(msg);
        } finally {
            ……
        }

        ……

        msg.recycleUnchecked();
}

loopOnce处理三斧头:取消息、分发消息、回收消息。同时Looper会监测消息执行时间,过长会打印日志,这个暂且不表。

  1. 取消息

    MessageQueue的next方法首先调用nativePollOnce;处理native层的消息。nativePollOnce就是调用NativeMessageQueue的pollOnce方法,其调用mLooper->pollOnce(timeoutMillis);。最终实现都是Looper的pollOnce方法,pollOnce会调用epoll_wait等待消息,填入的timeoutMillis表示等待时间,为0表示不等待,为负表示一直等待直到有事件到来。当Java层的Handler的sendMessage时,会使得native层epoll_wait返回,从而nativePollOnce返回,从而让现场回到java层,从MessageQueue中取的消息,然后调用handler的

  2. 分发消息

    handler的dispatchMessage方法

    /**
         * Handle system messages here.
         */
        public void dispatchMessage(@NonNull Message msg) {
            if (msg.callback != null) {
                handleCallback(msg);
            } else {
                if (mCallback != null) {
                    if (mCallback.handleMessage(msg)) {
                        return;
                    }
                }
                handleMessage(msg);
            }
        }
    

    先处理Message中自带的callback

  3. 回收消息

    msg.recycleUnchecked();
    

线程绑定该Looper对象,并不意味着其它线程不能访问,其它线程也是可以访问的,只不过将线程绑定Looper,访问起来要方便一点而已。

上面其实说的是Java层的Looper,因为java层Looper必然会创建关联的native层Looper。或者java层的Looper离不开native层的Looper,本质上是离不开epoll_wait实现的休眠和唤醒机制。

而Native层的Looper却可以离开java层的Looper。可以完成创建Native层的Looper,不需要创建java层Looper已经Native层的NativeMessageQueue(其只是与Java层沟通的桥梁,既然不需要创建Java层Looper,那么也不需要它)。Native层的Looper也可以不用将其保存在线程的局部空间,只要一个线程在循环中不断调用它的pollOnce方法则就会休眠在它上面,当其它线程调用该looper对象的wake方法,wake方法就会想mWakeFd发送数据,则监听的epoll_wait就会返回,休眠在它上面的线程就会醒来。






—具体分析—————

先看官方介绍:

A Handler allows you to send and process Messageand Runnable objects associated with a thread'sMessageQueue`

There are two main uses for a Handler: (1) to schedule messages and runnables to be executed at some point in the future; and (2) to enqueue an action to be performed on a different thread than your own.

Scheduling messages is accomplished with the post(Runnable), postAtTime(java.lang.Runnable, long), [postDelayed(Runnable, Object, long)] (https://developer.android.google.cn/reference/android/os/Handler#postDelayed(java.lang.Runnable,%20java.lang.Object,%20long)), sendEmptyMessage(int),sendMessage(Message),sendMessageAtTime(Message, long), andsendMessageDelayed(Message, long). methods. The post versions allow you to enqueue Runnable objects to be called by the message queue when they are received; the sendMessage versions allow you to enqueue a Messageobject containing a bundle of data that will be processed by the Handler'shandleMessage(Message)` method (requiring that you implement a subclass of Handler)

再上一张框架图。
在这里插入图片描述
java层一个线程只能绑定一个looper,而native层如果是监听文件,不用发消息的话好像不用绑定,直接new 一个looper 然后,在looper的pollOnce中调用epoll_wai

最后开始Looper之旅:创建—注册—取消息—处理消息—回收消息。

1 looper创建

1.1 java层looper创建

Looper.prepare()

/** Initialize the current thread as a looper.
      * This gives you a chance to create handlers that then reference
      * this looper, before actually starting the loop. Be sure to call
      * {@link #loop()} after calling this method, and end it by calling
      * {@link #quit()}.
      */
    public static void prepare() {
        prepare(true);
    }
private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(quitAllowed));
    }
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

sThreadLocal是Looper类的ThreadLocal类型静态变量
在这里插入图片描述

ThreadLocal

ThreadLocal并不是真的将变量隐藏在线程内部,而是通过一个公有变量,这个变量任何线程都能访问,但是不同线程访问出来的值不一样,这个变量就是ThreadLocal。

ThreadLocal<Integer> local=new TheadLocal<Integer>(); //Interger代表value类型,这是泛型

当A线程执行下面的代码

local.set(100);

当B线程执行下面的代码

local.set(200)

则当A和B分别执行下面的代码的时候值不一样

local.get() //A线程执行得100,B线程执行得200

那么这种是怎么实现的呢,

当A线程调用local.set(100)时,ThreadLocal将自己作为key,传进来的100作为value存到线程关联的Java类Thread的ThreadLocalMap类成员threadLocals中,如果不存在ThreadLocal会创建该成员(通过createMap)方法。可参照上图深入理解。

/**
     * Sets the current thread's copy of this thread-local variable
     * to the specified value.  Most subclasses will have no need to
     * override this method, relying solely on the {@link #initialValue}
     * method to set the values of thread-locals.
     *
     * @param value the value to be stored in the current thread's copy of
     *        this thread-local.
     */
    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }
    /**
     * Create the map associated with a ThreadLocal. Overridden in
     * InheritableThreadLocal.
     *
     * @param t the current thread
     * @param firstValue value for the initial entry of the map
     */
    void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }

回到Looper。sThreadLocal 是Looper类的静态成员变量,其关联的值类型为Looper

static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

调用sThreadLocal 的set(new Looper(quitAllowed))方法将该sThreadLocal为key,新创建的looper对象为value存到线程的Thread的ThreadLocalMap中。下次要访问该Looper对象,只要通过Looper类就行,因为通过Looper类就访问到了静态成员sThreadLocal,通过该ThreadLocal对象就访问到了线程中该key对应value,即looper对象(调用ThreadLocal.get())方法。

通过Looper类访问Looper对象的方式:

final Looper me = myLooper();

看一下Looper对象的构造函数,其创建了MessageQueue和保存了线程的java Thread对象。

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

MessageQueue的创建,就会创建native层的MessageQueue

MessageQueue(boolean quitAllowed) {
        mQuitAllowed = quitAllowed;
        mPtr = nativeInit(); //mptr执行native层的MessageQueue
    }

1.2 native层的MessageQueue创建

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);
    return reinterpret_cast<jlong>(nativeMessageQueue);
}
NativeMessageQueue::NativeMessageQueue() :
        mPollEnv(NULL), mPollObj(NULL), mExceptionObj(NULL) {
    mLooper = Looper::getForThread();
    if (mLooper == NULL) {
        mLooper = new Looper(false);
        Looper::setForThread(mLooper);
    }
}

native层的Looper和java层Looper一点关系也没有,这里刚刚创建NativeMessageQueue时,显然还不存在looper,因此走下面的new looper流程,这里说一下native层“threadLocal”,线程独立的实现方法。

native “ThreadLocal”

native层实现方法与java层的ThreadLocal类似,或者说java层的ThreadLocal是参照了native层,因此这个是linux的函数。

int pthread_key_create (pthread_key_t *key, void (*destructor)(void *));
// Returns 0 on success, or a positive error number on error
int pthread_key_delete (pthread_key_t key);

// Returns 0 on success, or a positive error number on error
int pthread_setspecific (pthread_key_t key, const void *value);

// Returns pointer, or NULL if no thread-specific data is associated with key
void *pthread_getspecific (pthread_key_t key);

pthread_key_create为线程创建一个key,该key其它线程也可以使用,因此常设为全局变量。

pthread_key_delete 则在线程中删除该key,而pthread_setspecific 和pthread_getspecific 分别用于设置或者获取key对应的value。

回到Native层的Looper,其调用pthread_setspecific设置gTLSKey对应的value,这里的value指定为刚刚创建的looper,

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

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

    pthread_setspecific(gTLSKey, looper.get());

    if (old != nullptr) {
        old->decStrong((void*)threadDestructor);
    }
}
sp<Looper> Looper::getForThread() {
    int result = pthread_once(& gTLSOnce, initTLSKey);
    LOG_ALWAYS_FATAL_IF(result != 0, "pthread_once failed");
 //这里-------
    return (Looper*)pthread_getspecific(gTLSKey);
}

因此native层的“ThreadLocal”就是pthread_key_t 。

因此通过Looper类就可获取线程对应的Looper对象,因为通过Looper类能够访问pthread_key_t ,通过该key便可以从线程中读取对应的value,即Looper对象。这样就将线程和Looper对象绑定起来。

通过Looper类访问looper对象的方式:

Looper::getForThread()

native looper

mLooper = new Looper(false);

Looper::Looper(bool allowNonCallbacks)
    : mAllowNonCallbacks(allowNonCallbacks),
      mSendingMessage(false),
      mPolling(false),
      mEpollRebuildRequired(false),
      mNextRequestSeq(WAKE_EVENT_FD_SEQ + 1),
      mResponseIndex(0),
      mNextMessageUptime(LLONG_MAX) {
    mWakeEventFd.reset(eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC)); //构造唤醒事件的fd
    LOG_ALWAYS_FATAL_IF(mWakeEventFd.get() < 0, "Could not make wake event fd: %s", strerror(errno));

    AutoMutex _l(mLock);
    rebuildEpollLocked();重建Epoll事件
}

Epoll创建以及监听

创建Looper时,会做以下事情:

  1. 通过eventfd创建mWakeEventFd用于线程间通信去唤醒Looper的,当需要唤醒Looper时,就往里面写1
  2. 创建用于监听epoll_event的mEpollFd,并初始化mEpollFd要监听的epoll_event类型
  3. 通过epoll_ctl将mWakeEventFd注册到mEpollFd中,当mWakeEventFd有事件可读则唤醒Looper
  4. 如果mRequests不为空的话,说明前面注册了有要监听的fd,则遍历mRequests中的Request,将它初始化为epoll_event并通过epoll_ctl注册到mEpollFd中,当有可读事件同样唤醒Looper
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
        mEpollFd.reset();
    }

    // Allocate the new epoll instance and register the WakeEventFd.
    mEpollFd.reset(epoll_create1(EPOLL_CLOEXEC));
    LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance: %s", strerror(errno));

    epoll_event wakeEvent = createEpollEvent(EPOLLIN, WAKE_EVENT_FD_SEQ);
    //加入epoll 监听
    int result = epoll_ctl(mEpollFd.get(), EPOLL_CTL_ADD, mWakeEventFd.get(), &wakeEvent);
    LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake event fd to epoll instance: %s",
                        strerror(errno));

    for (const auto& [seq, request] : mRequests) {
        epoll_event eventItem = createEpollEvent(request.getEpollEvents(), seq);
        
        //加入epoll监听
        int epollResult = epoll_ctl(mEpollFd.get(), 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));
        }
    }
}

2 Looper启动启动

Looper.loop()

/**
     * Run the message queue in this thread. Be sure to call
     * {@link #quit()} to end the loop.
     */
    @SuppressWarnings("AndroidFrameworkBinderIdentity")
    public static void loop() {
        final Looper me = myLooper();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        if (me.mInLoop) {
            Slog.w(TAG, "Loop again would have the queued messages be executed"
                    + " before this one completed.");
        }

        me.mInLoop = true;

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

        // Allow overriding a threshold with a system prop. e.g.
        // adb shell 'setprop log.looper.1000.main.slow 1 && stop && start'
        final int thresholdOverride =
                SystemProperties.getInt("log.looper."
                        + Process.myUid() + "."
                        + Thread.currentThread().getName()
                        + ".slow", 0);

        me.mSlowDeliveryDetected = false;

        for (;;) {
              //死循环,除非调用了quit方法
            if (!loopOnce(me, ident, thresholdOverride)) {
                return;
            }
        }
    }
/**
     * Poll and deliver single message, return true if the outer loop should continue.
     */
    @SuppressWarnings("AndroidFrameworkBinderIdentity")
    private static boolean loopOnce(final Looper me,
            final long ident, final int thresholdOverride) {

        Message msg = me.mQueue.next(); // might block
        if (msg == null) {
            // No message indicates that the message queue is quitting.
            return false;
        }

        // This must be in a local variable, in case a UI event sets the logger
        final Printer logging = me.mLogging;
        if (logging != null) {
            logging.println(">>>>> Dispatching to " + msg.target + " "
                    + msg.callback + ": " + msg.what);
        }
        // Make sure the observer won't change while processing a transaction.
        final Observer observer = sObserver;

        final long traceTag = me.mTraceTag;
        long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
        long slowDeliveryThresholdMs = me.mSlowDeliveryThresholdMs;
        if (thresholdOverride > 0) {
            slowDispatchThresholdMs = thresholdOverride;
            slowDeliveryThresholdMs = thresholdOverride;
        }
        final boolean logSlowDelivery = (slowDeliveryThresholdMs > 0) && (msg.when > 0);
        final boolean logSlowDispatch = (slowDispatchThresholdMs > 0);

        final boolean needStartTime = logSlowDelivery || logSlowDispatch;
        final boolean needEndTime = logSlowDispatch;

        if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
            Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
        }

        final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
        final long dispatchEnd;
        Object token = null;
        if (observer != null) {
            token = observer.messageDispatchStarting();
        }
        long origWorkSource = ThreadLocalWorkSource.setUid(msg.workSourceUid);
        try {
            msg.target.dispatchMessage(msg);
            if (observer != null) {
                observer.messageDispatched(token, msg);
            }
            dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
        } catch (Exception exception) {
            if (observer != null) {
                observer.dispatchingThrewException(token, msg, exception);
            }
            throw exception;
        } finally {
            ThreadLocalWorkSource.restore(origWorkSource);
            if (traceTag != 0) {
                Trace.traceEnd(traceTag);
            }
        }
        if (logSlowDelivery) {
            if (me.mSlowDeliveryDetected) {
                if ((dispatchStart - msg.when) <= 10) {
                    Slog.w(TAG, "Drained");
                    me.mSlowDeliveryDetected = false;
                }
            } else {
                if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery",
                        msg)) {
                    // Once we write a slow delivery log, suppress until the queue drains.
                    me.mSlowDeliveryDetected = true;
                }
            }
        }
        if (logSlowDispatch) {
            showSlowLog(slowDispatchThresholdMs, dispatchStart, dispatchEnd, "dispatch", 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);
        }

        msg.recycleUnchecked();

        return true;
    }

总结一下就是下面的结构,取出消息,分发消息,回收消息。

public static void loop() {
    ……

    for (;;) {
        Message msg = queue.next(); // might block

        ……

        try {
            msg.target.dispatchMessage(msg);
        } finally {
            ……
        }

        ……

        msg.recycleUnchecked();
    }
}

3. 注册(发消息)

3.1 native层注册

  1. 文件注册

looper对象的addFd方法

events指定了要监听上面事件,是fd中有数据时的事件还是其它,events与epoll_event的events一一对应。构建epoll_event,其中epool_event的events为该events转化过的events,epoll_event的data为联合类型,这里指定了其中的u64字段存储seq,Looper为每一个fd创建一个唯一seq。当事件到来时,从返回的epoll_event中的data.u64就可以获取seq值,再从looper的mSequenceNumberByFd成员就可指定对应的fd。

同时,为每一个注册的fd构建一个Request对象,存储在mRequests中。其ident也标识了该fd,当fd指定了callback时,ident为负数POLL_CALLBACK(-2),ident 表示singal indentifier,信号标识符。用于标识到来的事件

当事件来的时候,从seq获得Request对象,然后通过Request对象、seq、events构造Response对象,并将其放入mResponses队列中。只有文件fd才构造Request对象并加入mRequests列表,同时当epoll_wait返回的时候才构造Response对象并加入到mResponses列表中。

文件fd都会指定一个callback,因此到epoll监听到事件的时候,当looper进入到epoll_wait时就会知道,然后就执行callback而不会构造消息。

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

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

    { // acquire lock
        AutoMutex _l(mLock);
        // There is a sequence number reserved for the WakeEventFd.
        if (mNextRequestSeq == WAKE_EVENT_FD_SEQ) mNextRequestSeq++;
        const SequenceNumber seq = mNextRequestSeq++;

        Request request;
        request.fd = fd;
        request.ident = ident;
        request.events = events;
        request.callback = callback;
        request.data = data;

        epoll_event eventItem = createEpollEvent(request.getEpollEvents(), seq);
        auto seq_it = mSequenceNumberByFd.find(fd);
        if (seq_it == mSequenceNumberByFd.end()) {
            int epollResult = epoll_ctl(mEpollFd.get(), EPOLL_CTL_ADD, fd, &eventItem);
            if (epollResult < 0) {
                ALOGE("Error adding epoll events for fd %d: %s", fd, strerror(errno));
                return -1;
            }
            mRequests.emplace(seq, request);
            mSequenceNumberByFd.emplace(fd, seq);
        } else {
            int epollResult = epoll_ctl(mEpollFd.get(), EPOLL_CTL_MOD, fd, &eventItem);
            if (epollResult < 0) {
                if (errno == ENOENT) {
                    // 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 other 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.get(), EPOLL_CTL_ADD, fd, &eventItem);
                    if (epollResult < 0) {
                        ALOGE("Error modifying or adding epoll events for fd %d: %s",
                                fd, strerror(errno));
                        return -1;
                    }
                    scheduleEpollRebuildLocked();
                } else {
                    ALOGE("Error modifying epoll events for fd %d: %s", fd, strerror(errno));
                    return -1;
                }
            }
            const SequenceNumber oldSeq = seq_it->second;
            mRequests.erase(oldSeq);
            mRequests.emplace(seq, request);
            seq_it->second = seq;
        }
    } // release lock
    return 1;
}
void NativeMessageQueue::setFileDescriptorEvents(int fd, int events) {
    if (events) {
        int looperEvents = 0;
        if (events & CALLBACK_EVENT_INPUT) {
            looperEvents |= Looper::EVENT_INPUT;
        }
        if (events & CALLBACK_EVENT_OUTPUT) {
            looperEvents |= Looper::EVENT_OUTPUT;
        }
        mLooper->addFd(fd, Looper::POLL_CALLBACK, looperEvents, this,
                reinterpret_cast<void*>(events));
    } else {
        mLooper->removeFd(fd);
    }
}
  1. 添加Handler和消息:Looper:sendMessage

一个是sendMessage,消息及时分发。还有一个sendMessageDelayed,延时分发消息

看一下Message结构,只有一个what字段,指明这是上面消息

struct Message {
    Message() : what(0) { }
    Message(int w) : what(w) { }

    /* The message type. (interpretation is left up to the handler) */
    int what;
};
/**
     * Enqueues a message to be processed by the specified handler.
     *
     * The handler must not be null.
     * This method can be called on any thread.
     */
void Looper::sendMessage(const sp<MessageHandler>& handler, const Message& message)
 /**
     * Enqueues a message to be processed by the specified handler after all pending messages
     * after the specified delay.
     *
     * The time delay is specified in uptime nanoseconds.
     * The handler must not be null.
     * This method can be called on any thread.
     */

void Looper::sendMessageDelayed(nsecs_t uptimeDelay, const sp<MessageHandler>& handler,
        const Message& message) 

sendMessage

void Looper::sendMessage(const sp<MessageHandler>& handler, const Message& message) {
    nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
    sendMessageAtTime(now, 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();
        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

    // Wake the poll loop only when we enqueue a new message at the head.
    if (i == 0) {
        wake();
    }
}

Looper中含有MessageEnvelope列表mMessageEnvelope成员,列表中的元素按照时间顺序从小到大排列,代表了Looper待处理的消息,当Looper的sendMessage被调用的时候,参数Message就被包装为MessageEnvelope放入该队列中。这里也用到了等待服务模型(我自己命名的),即众多消息来的时候,先将第一个消息入队列并处理,后面的消息进入队列排队,等第一个消息处理完后,再处理队列中的消息

 // Wake the poll loop only when we enqueue a new message at the head.
    if (i == 0) { //表示是第一个入队的消息
        wake();
    }

Looper的mMessageEnvelopes针对的只是Handler。

3.2 Java层发送消息

Message,不想Native层的Message只有一个what成员,Java层Message含有what表示消息类型,arg1、arg2、obj、data用来传递数据。Target表示目标handler,即该消息要发送给该Handler处理。如果Target为null,表示这是barrier消息。when表示这个消息应该什么时候处理,如果没有设置when,则在调用handler的sendxxx或者postxxx时设置为当前时间,表示立即处理。设置该when表示用户希望该消息应该在什么时候处理。flag存储消息的标识,如果设置了FLAG_ASYNCHRONOUS标志,标识这是一个异步消息。callback标识Message中的回调,handler的dispatchMessage中会检查是否设置了该成员,设置了就调用该callback,然后返回,否则就调用Handler的mCallback成员,没有设置才最后调用Handler的handleMessage。同时Message实现了消息池,需要message的时候可以去池子里拿(通过obtain方法),用了之后会被回收(被Looper).

/**
 *
 * Defines a message containing a description and arbitrary data object that can be
 * sent to a {@link Handler}.  This object contains two extra int fields and an
 * extra object field that allow you to not do allocations in many cases.
 *
 * <p class="note">While the constructor of Message is public, the best way to get
 * one of these is to call {@link #obtain Message.obtain()} or one of the
 * {@link Handler#obtainMessage Handler.obtainMessage()} methods, which will pull
 * them from a pool of recycled objects.</p>
 */
public final class Message implements Parcelable {
    /**
     * User-defined message code so that the recipient can identify
     * what this message is about. Each {@link Handler} has its own name-space
     * for message codes, so you do not need to worry about yours conflicting
     * with other handlers.
     */
    public int what;

    /**
     * arg1 and arg2 are lower-cost alternatives to using
     * {@link #setData(Bundle) setData()} if you only need to store a
     * few integer values.
     */
    public int arg1;

    /**
     * arg1 and arg2 are lower-cost alternatives to using
     * {@link #setData(Bundle) setData()} if you only need to store a
     * few integer values.
     */
    public int arg2;

    /**
     * An arbitrary object to send to the recipient.  When using
     * {@link Messenger} to send the message across processes this can only
     * be non-null if it contains a Parcelable of a framework class (not one
     * implemented by the application).   For other data transfer use
     * {@link #setData}.
     *
     * <p>Note that Parcelable objects here are not supported prior to
     * the {@link android.os.Build.VERSION_CODES#FROYO} release.
     */
    public Object obj;

    /**
     * Optional Messenger where replies to this message can be sent.  The
     * semantics of exactly how this is used are up to the sender and
     * receiver.
     */
    public Messenger replyTo;

    /**
     * Indicates that the uid is not set;
     *
     * @hide Only for use within the system server.
     */
    public static final int UID_NONE = -1;

    /**
     * Optional field indicating the uid that sent the message.  This is
     * only valid for messages posted by a {@link Messenger}; otherwise,
     * it will be -1.
     */
    public int sendingUid = UID_NONE;

    /**
     * Optional field indicating the uid that caused this message to be enqueued.
     *
     * @hide Only for use within the system server.
     */
    public int workSourceUid = UID_NONE;

    /** If set message is in use.
     * This flag is set when the message is enqueued and remains set while it
     * is delivered and afterwards when it is recycled.  The flag is only cleared
     * when a new message is created or obtained since that is the only time that
     * applications are allowed to modify the contents of the message.
     *
     * It is an error to attempt to enqueue or recycle a message that is already in use.
     */
    /*package*/ static final int FLAG_IN_USE = 1 << 0;

    /** If set message is asynchronous */
    /*package*/ static final int FLAG_ASYNCHRONOUS = 1 << 1;

    /** Flags to clear in the copyFrom method */
    /*package*/ static final int FLAGS_TO_CLEAR_ON_COPY_FROM = FLAG_IN_USE;

    @UnsupportedAppUsage
    /*package*/ int flags;

    /**
     * The targeted delivery time of this message. The time-base is
     * {@link SystemClock#uptimeMillis}.
     * @hide Only for use within the tests.
     */
    @UnsupportedAppUsage
    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
    public long when;

    /*package*/ Bundle data;

    @UnsupportedAppUsage
    /*package*/ Handler target;

    @UnsupportedAppUsage
    /*package*/ Runnable callback;

    // sometimes we store linked lists of these things
    @UnsupportedAppUsage
    /*package*/ Message next;

    /** @hide */
    public static final Object sPoolSync = new Object();
    private static Message sPool;
    private static int sPoolSize = 0;

    private static final int MAX_POOL_SIZE = 50;

    private static boolean gCheckRecycle = true;

    /**
     * Return a new Message instance from the global pool. Allows us to
     * avoid allocating new objects in many cases.
     */
    public static Message obtain() {
        synchronized (sPoolSync) {
            if (sPool != null) {
                Message m = sPool;
                sPool = m.next;
                m.next = null;
                m.flags = 0; // clear in-use flag
                sPoolSize--;
                return m;
            }
        }
        return new Message();
    }

    /**
     * Same as {@link #obtain()}, but copies the values of an existing
     * message (including its target) into the new one.
     * @param orig Original message to copy.
     * @return A Message object from the global pool.
     */
    public static Message obtain(Message orig) {
        Message m = obtain();
        m.what = orig.what;
        m.arg1 = orig.arg1;
        m.arg2 = orig.arg2;
        m.obj = orig.obj;
        m.replyTo = orig.replyTo;
        m.sendingUid = orig.sendingUid;
        m.workSourceUid = orig.workSourceUid;
        if (orig.data != null) {
            m.data = new Bundle(orig.data);
        }
        m.target = orig.target;
        m.callback = orig.callback;

        return m;
    }

java层发送消息都是通过Handler的方法(native层是通过Looper的sendMessage)和MessageQueue,Handler发送的有Post消息、Send消息、Barrier消息。而MessageQueue发送的只有Barrier消息。Post版本发送callback消息(有callback成员的message),而send版本则是一般消息(没有设置callback成员。

Handler方法
new Handler(@Nullable Callback callback, boolean async)
 post(Runnable),
 postAtTime(java.lang.Runnable, long), 
 postDelayed(Runnable, Object, long), 

 sendEmptyMessage(int), 
 sendMessage(Message), 
 sendMessageAtTime(Message, long), 
 sendMessageDelayed(Message, long)
MessageQueue方法:
  postSyncBarrier()
  postSyncBarrier(long when)
  removeSyncBarrier(token)

3.2.1 barrier消息

MessageQueue


int postSyncBarrier() {
        return postSyncBarrier(SystemClock.uptimeMillis());
    }
private int postSyncBarrier(long when) {
        // Enqueue a new sync barrier token.
        // We don't need to wake the queue because the purpose of a barrier is to stall it.
        synchronized (this) {
            final int token = mNextBarrierToken++;
            final Message msg = Message.obtain();
            msg.markInUse();
            msg.when = when;
            msg.arg1 = token;

            Message prev = null;
            Message p = mMessages;
            if (when != 0) {
                while (p != null && p.when <= when) {
                    prev = p;
                    p = p.next;
                }
            }
            if (prev != null) { // invariant: p == prev.next
                msg.next = p;
                prev.next = msg;
            } else {
                msg.next = p;
                mMessages = msg;
            }
            return token;
        }
    }

可见barrier消息就是Handler为null的消息,MessageQueue开发分发消息的时会根据handler是否为null识别出是否为barrier消息。返回的token用来标识该Barrier消息,后面调用removeSyncBarrier方法可以移除该消息。

常用的方法:

 
token= mHandler.getLooper().getQueue().postSyncBarrier();
mHandler.getLooper().getQueue().removeSyncBarrier(token)

3.2.2 普通消息

这个没有啥子好说的

3.2.3 Callback消息

CalBack有两种,一种是对Message的callback赋值,使用PostXXX方法发送Callback消息,先构造message,然后对message的callback进行赋值。 最后再调用sendxxx的方法进入messageQueue。

public final boolean post(@NonNull Runnable r) {
       return  sendMessageDelayed(getPostMessage(r), 0);
    }
private static Message getPostMessage(Runnable r) {
        Message m = Message.obtain();
        m.callback = r;
        return m;
    }
public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }

另外一种是设置Handler的mCallback成员,当有MessageQueue调用Handler分发消息的时候,如果消息没有callback成员,则会调用Handler的mCallback成员,没有的话才最后调用Handler的handleMessage方法。App端是不能设置mCallbackd,因为有@UnsupportedAppUsage注释,App访问不了。设置mCallBack的方法就是Handler的构造函数调用的时候设置。

* @hide
     */
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public Handler(@Nullable Callback callback, boolean async) {
        if (FIND_POTENTIAL_LEAKS) {
            final Class<? extends Handler> klass = getClass();
            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                    (klass.getModifiers() & Modifier.STATIC) == 0) {
                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                    klass.getCanonicalName());
            }
        }

        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread " + Thread.currentThread()
                        + " that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

3.2.4 Handler的产生

Handler的构函数如下,总结就是指定如下几项成员:

  1. mLooper对:指定Handler关联的Looper对象,不指定looper对象,使用此时线程的looper对象
  2. mCallback:指定了mCallback,当MessageQueue分发消息的时候,如果消息没有指定callback,就调用handler的mCallback,如果没有最后才调用handleMessage
  3. mAsynchronous:是否为异步Handler,通过异步Handler发送的消息全是异步消息,其Message的flag会被设置FLAG_ASYNCHRONOUS标志。
public Handler() {
        this(null, false);
    }
@Deprecated
    public Handler(@Nullable Callback callback) {
        this(callback, false);
    }
public Handler(@NonNull Looper looper) {
        this(looper, null, false);
    }
public Handler(@NonNull Looper looper, @Nullable Callback callback) {
        this(looper, callback, false);
    }
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    public Handler(boolean async) {
        this(null, async);
    }
public Handler(@Nullable Callback callback, boolean async)
@UnsupportedAppUsage
    public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async)

最好是创建一个继承Handler的静态内部类来使用Handler,应为要重写handleMessage,因此就必定继承Handler,而继承Handler有有三种方式,一种是非静态内部类,一种是匿名内部类,一种是静态内部类。前两种都会持有外部对象,一般这里的外部对象就是MainActivity,而通过handler发送消息时,message是持有该handler对象的(这样MessageQueue才知道消息应该发给谁处理),message没有被回收之前,Handler是不会被回收的,而Handler有持有外部类也就是MainActivity,导致Handler没有被回收之前,MainActivity是不会被回收的,当Message一直没有被回收,那么MainActivyt也就不会被回收,这就会导致内存泄漏问题,一般会提示:

This Handler class should be static or leaks might occur。

4. 取消息与处理消息

4.1 获取native层消息并处理

MessageQueue的next方法,先处理native层的MessageQueue

@UnsupportedAppUsage
    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();
            }
          //获取native层消息并处理
            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;
                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.
                        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;
                    }
                } else {
                    // No more messages.
                    nextPollTimeoutMillis = -1;
                }

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

                // If first time idle, then get the number of idlers to run.
                // Idle handles only run if the queue is empty or if the first message
                // in the queue (possibly a barrier) is due to be handled in the future.
                if (pendingIdleHandlerCount < 0
                        && (mMessages == null || now < mMessages.when)) {
                    pendingIdleHandlerCount = mIdleHandlers.size();
                }
                if (pendingIdleHandlerCount <= 0) {
                    // No idle handlers to run.  Loop and wait some more.
                    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;
        }
    }

nativePollOnce

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

pollOnce为轮询一次,如果没有事件,则在指定时间醒来,如果事件为0,则不休眠立即起来,为负数,则一直等待知道有事件到来才醒来。这里的指定事件为0.

/**
     * Waits for events to be available, with optional timeout in milliseconds.
     * Invokes callbacks for all file descriptors on which an event occurred.
     *
     * If the timeout is zero, returns immediately without blocking.
     * If the timeout is negative, waits indefinitely until an event appears.
     *
     * Returns POLL_WAKE if the poll was awoken using wake() before
     * the timeout expired and no callbacks were invoked and no other file
     * descriptors were ready.
     *
     * Returns POLL_CALLBACK if one or more callbacks were invoked.
     *
     * Returns POLL_TIMEOUT if there was no data before the given
     * timeout expired.
     *
     * Returns POLL_ERROR if an error occurred.
     *
     * Returns a value >= 0 containing an identifier if its file descriptor has data
     * and it has no callback function (requiring the caller here to handle it).
     * In this (and only this) case outFd, outEvents and outData will contain the poll
     * events and data associated with the fd, otherwise they will be set to NULL.
     *
     * This method does not return until it has finished invoking the appropriate callbacks
     * for all file descriptors that were signalled.
     */
    int pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData);
    inline int pollOnce(int timeoutMillis) {
        return pollOnce(timeoutMillis, nullptr, nullptr, nullptr);
    }
  1. 优先处理mResponses里的Response,即来自fd的事件
  2. 如果没有需处理的Response,再调用pollInner
int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
    int result = 0;
    for (;;) {
        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 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 != nullptr) *outFd = fd;
                if (outEvents != nullptr) *outEvents = events;
                if (outData != nullptr) *outData = data;
                return ident;
            }
        }

        if (result != 0) {
#if DEBUG_POLL_AND_WAKE
            ALOGD("%p ~ pollOnce - returning result %d", this, result);
#endif
            if (outFd != nullptr) *outFd = 0;
            if (outEvents != nullptr) *outEvents = 0;
            if (outData != nullptr) *outData = nullptr;
            return result;
        }
       /这里=====
        result = pollInner(timeoutMillis);
    }
}
std::unordered_map<int /*fd*/, SequenceNumber> mSequenceNumberByFd;  // guarded by mLock
using SequenceNumber = uint64_t;
int Looper::pollInner(int timeoutMillis) {
#if DEBUG_POLL_AND_WAKE
    ALOGD("%p ~ pollOnce - waiting: timeoutMillis=%d", this, timeoutMillis);
#endif

    // Adjust the timeout based on when the next message is due.
    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;
        }
#if DEBUG_POLL_AND_WAKE
        ALOGD("%p ~ pollOnce - next message in %" PRId64 "ns, adjusted timeout: timeoutMillis=%d",
                this, mNextMessageUptime - now, timeoutMillis);
#endif
    }

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

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

    struct epoll_event eventItems[EPOLL_MAX_EVENTS];
    int eventCount = epoll_wait(mEpollFd.get(), 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;
    }

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

    // Handle all events.
#if DEBUG_POLL_AND_WAKE
    ALOGD("%p ~ pollOnce - handling events from %d fds", this, eventCount);
#endif

    for (int i = 0; i < eventCount; i++) {
        const SequenceNumber seq = eventItems[i].data.u64;
        uint32_t epollEvents = eventItems[i].events;
        if (seq == WAKE_EVENT_FD_SEQ) {
            if (epollEvents & EPOLLIN) {
                awoken();
            } else {
                ALOGW("Ignoring unexpected epoll events 0x%x on wake event fd.", epollEvents);
            }
        } else {
            const auto& request_it = mRequests.find(seq);
            if (request_it != mRequests.end()) {
                const auto& request = request_it->second;
                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;
                mResponses.push({.seq = seq, .events = events, .request = request});
            } else {
                ALOGW("Ignoring unexpected epoll events 0x%x for sequence number %" PRIu64
                      " that is no longer registered.",
                      epollEvents, seq);
            }
        }
    }
Done: ;

    // Invoke pending message callbacks.
    mNextMessageUptime = LLONG_MAX;
    while (mMessageEnvelopes.size() != 0) {
        nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
        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);
            } // 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();

    // 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);
            if (callbackResult == 0) {
                AutoMutex _l(mLock);
                removeSequenceNumberLocked(response.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();
            result = POLL_CALLBACK;
        }
    }
    return result;
}

这里有两种处理,先调用epoll_wait等待fd事件,fd事件到来后,如果是wake事件,则调用 awoken();函数,否则将这些事件包装为Response对象加入到mResponses列表中,然后进入done部分。进入done部分后依次进行两种处理

处理1:Handler消息处理,遍历mMessageEnvelops列表,取出列表的元素MessageEnvelop中的message(拆封)和对应的Handler,然后调用Handler的handleMessage(message)。MessageEnvelope被取出后就会从mMessageEnvelops中移除。

处理2:处理完Handler的消息后,开始处理fd消息,遍历mResponses列表,取出Response对象,取出其中Request类成员request的callback、fd、data和Response的events(监听的事件),对于request的ident等于POLL_CALLBACK的Resonse就会调用callback的handleEvent(fd, events, data),这里的data其实是seq(注册的时候传入的)。fd事件被处理后不一定会消息对fd的监听,还要看**handleEvent的返回值,如果为0,则取消监听,为1则不取消监听。**而ident若不为POLL_CALLBACK(-2)则就是一个正值,表示应该不这个事件传出去,而不是自己处理。该处理不在pollinner中,而在pollOnce中。

为什么不处理完后不清除mResponses中的元素呢,因为此时只处理了ident为POLL_CALLBACK的Response元素,还有ident大于0的Resonse元素没有处理,因此此时还不能清空,这些ident大于0的response元素在下一轮的pollonce开头处理,而清空则在接下来的pollinner开头处理。

处理ident大于0的元素,在进入pollonce中一开头,便遍历mResponses中的ident大于0的Response对象,用mResponseIndex 记录其位置,然后返回pollonce函数,将fd、events、data传出去,在下次looper进入pollonce的时候又开始这个流程(从mResponseIndex 所指位置开始),直到将所有ident大于0的fd事件处理完后才进入pollinner函数,该函数一开头便情况mResponses和重置mmResponseIndex 。但在有java层Looper存在的情况下,mAllowNonCallbacks为false,也就意味着fd注册的时候必须有callback,没有callback即ident大于0的情况是不被允许注册的。

4.2 java层获取消息与处理

在java层MessageQueue的next方法中,先处理native层消息,处理完之后再从消息链表中取出一个消息,不管是什么消息都会调用msg.target.dispatchMessage(msg)进行分发处理。

@UnsupportedAppUsage
    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();
            }
          //获取native层消息并处理
            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;
                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.
                        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;
                    }
                } else {
                    // No more messages.
                    nextPollTimeoutMillis = -1;
                }

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

                // If first time idle, then get the number of idlers to run.
                // Idle handles only run if the queue is empty or if the first message
                // in the queue (possibly a barrier) is due to be handled in the future.
                if (pendingIdleHandlerCount < 0
                        && (mMessages == null || now < mMessages.when)) {
                    pendingIdleHandlerCount = mIdleHandlers.size();
                }
                if (pendingIdleHandlerCount <= 0) {
                    // No idle handlers to run.  Loop and wait some more.
                    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;
        }
    }

获取消息后,调用msg.target.dispatchMessage(msg)进行分发处理进行处理

/**
     * Handle system messages here.
     */
    public void dispatchMessage(@NonNull Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

5. 停止

Looper.quit()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值