Handler机制及原理探究

来源:互联网 发布:网络流行文化 编辑:程序博客网 时间:2024/05/19 20:38

Handler使用简单功能强大,常被用作线程间传递消息的组件,而且还可以用于跨进程。

消息机制背后有包括Looper ,MessageQueue管理和分发消息的实现,同时在Native层也单独实现了一套类似的机制,接收和处理Native层的消息。Java层和Native层的消息循环是独立运行的,彼此的Message并不会互通,Native使用epoll机制来实现监听及触发,并向JAVA层提供了接口。

这里从Java层开始深入探究下Handler和消息机制背后实现的原理。


初探Handler

本章只作为入口,先从宏观上去了解其中的架构,之后再做深入分析。

代码架构

Handler本身只负责发送和处理接收到的消息,其背后有一个消息循环为它管理和提供消息。
MessageQueue是管理着Message链表;而Looper是消息循环的主体,负责循环从MessageQueue中获取需要处理的新消息并向Handler输送。
这里写图片描述

其中MessageQueue有部分核心实现在native层(后续会讲到)。

MessageQueue.java   private native static long nativeInit();   private native static void nativeDestroy(long ptr);   private native void nativePollOnce(long ptr, int timeoutMillis); /*non-static for callbacks*/   private native static void nativeWake(long ptr);   private native static boolean nativeIsPolling(long ptr);   private native static void nativeSetFileDescriptorEvents(long ptr, int fd, int events);

native方法实现在JNI层的android_os_MessageQueue.cpp:

android_os_MessageQueue.cppstatic const JNINativeMethod gMessageQueueMethods[] = {    /* name, signature, funcPtr */    { "nativeInit", "()J", (void*)android_os_MessageQueue_nativeInit },    { "nativeDestroy", "(J)V", (void*)android_os_MessageQueue_nativeDestroy },    { "nativePollOnce", "(JI)V", (void*)android_os_MessageQueue_nativePollOnce },    { "nativeWake", "(J)V", (void*)android_os_MessageQueue_nativeWake },    { "nativeIsPolling", "(J)Z", (void*)android_os_MessageQueue_nativeIsPolling },    { "nativeSetFileDescriptorEvents", "(JII)V",            (void*)android_os_MessageQueue_nativeSetFileDescriptorEvents },};

什么是Handler?

打开Handler.java,先看下googler留给开发者留的一段说明:

/** * A Handler allows you to send and process {@link Message} and Runnable * objects associated with a thread's {@link MessageQueue}.  Each Handler * instance is associated with a single thread and that thread's message * queue.  When you create a new Handler, it is bound to the thread / * message queue of the thread that is creating it -- from that point on, * it will deliver messages and runnables to that message queue and execute * them as they come out of the message queue. *  * <p>There are two main uses for a Handler: (1) to schedule messages and * runnables to be executed as some point in the future; and (2) to enqueue * an action to be performed on a different thread than your own. *  * <p>Scheduling messages is accomplished with the * {@link #post}, {@link #postAtTime(Runnable, long)}, * {@link #postDelayed}, {@link #sendEmptyMessage}, * {@link #sendMessage}, {@link #sendMessageAtTime}, and * {@link #sendMessageDelayed} methods.  The <em>post</em> versions allow * you to enqueue Runnable objects to be called by the message queue when * they are received; the <em>sendMessage</em> versions allow you to enqueue * a {@link Message} object containing a bundle of data that will be * processed by the Handler's {@link #handleMessage} method (requiring that * you implement a subclass of Handler). *  * <p>When posting or sending to a Handler, you can either * allow the item to be processed as soon as the message queue is ready * to do so, or specify a delay before it gets processed or absolute time for * it to be processed.  The latter two allow you to implement timeouts, * ticks, and other timing-based behavior. *  * <p>When a * process is created for your application, its main thread is dedicated to * running a message queue that takes care of managing the top-level * application objects (activities, broadcast receivers, etc) and any windows * they create.  You can create your own threads, and communicate back with * the main application thread through a Handler.  This is done by calling * the same <em>post</em> or <em>sendMessage</em> methods as before, but from * your new thread.  The given Runnable or Message will then be scheduled * in the Handler's message queue and processed when appropriate. */

既然决定来了就不能放过每个细节,记录下重点。
运作方式:
每一个Handler实例只与一个单独的Thread和这个Thread的MessageQueue关联;
当我们在Thread中创建一个新的Handler时,会绑定这个Thread和Thread的MessageQueue,之后Handler允许我们向MessageQueue发送Message和Runnable,并在消息出列时处理它们。

Handler的2个主要用途:
1. 让Message和Runnable可以延迟执行;
2. 在另外一个线程中执行处理。

用法:
通过Post开头和sendMessage开头的方法可以发送消息到MessageQueue。
1. post开头的方法可以向队列插入Runnable;
2. sendMessage开头的方法则用于来送Message,Message将在handleMessage方法中被处理。
3. post和send方法既可以让消息“实时”被处理(相对于延时),也可以设置特定的时延,延时去处理。

建议:
应用进程中的的主线程是专门用于管理顶层的数据的,例如activity/广播/窗口等,不宜处理其他我们定义的耗时操作,因此我们应该创建自己的工作线程,通过Handler来向线程的MessageQueue发送要执行的任务。

三个需要理解的问题

看完上面这段话,有3个疑问需要探究:
1. Handler如何与Thread关联?
2. Thread和MessageQueue的关系是?
3. MessageQueue如何运作?它如何管理Runnable和Message?

后面对这些问题一一破解。


从如何使用Handler开始

怎么样才能使Handler正常运作?

例子1——定义在子线程的Handler

public class MainActivity extends AppCompatActivity {    Handler mHandler;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        Log.i("handler.demo", "Main Thread:" + Thread.currentThread().toString());        new MyThread().start();        //确保Handler已经在子线程中实例化        try {            Thread.sleep(500);        } catch (InterruptedException e) {            e.printStackTrace();        }        mHandler.post(new Runnable() {            @Override            public void run() {                Log.i("handler.demo", "Running in Thread:" + Thread.currentThread().toString());            }        });    }    class MyThread extends  Thread{        @Override        public void run() {            Looper.prepare();            mHandler = new Handler();            Looper.loop();        }    }}

Log输出,runnable的run被调用,而且运行在子线程Thread-4中:

06-10 16:48:51.077 17181-17181/? I/handler.demo: Main Thread:Thread[main,5,main]06-10 16:48:52.078 17181-17199/com.example.willis.myapplication I/handler.demo: Running in Thread:Thread[Thread-4,5,main]

例子2——定义在主线程中的Handler

将上面的例子稍作修改,就可以改成子线程向主线程Handler发送消息:

public class MainActivity extends AppCompatActivity {    Handler mHandler = null;    Object mLock = new Object();    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        Log.i("handler.demo", "Main Thread:" + Thread.currentThread().toString());        mHandler = new Handler();        new MyThread().start();    }    class MyThread extends  Thread{        @Override        public void run() {            mHandler.post(new Runnable() {                @Override                public void run() {                    Log.i("handler.demo", "Running in Thread:" + Thread.currentThread().toString());                }            });        }    }}

Log输出看到Runnable.run()就在主线程执行:

06-10 17:00:24.073 17526-17526/com.example.willis.myapplication I/handler.demo: Main Thread:Thread[main,5,main]06-10 17:00:24.095 17526-17526/com.example.willis.myapplication I/handler.demo: Running in Thread:Thread[main,5,main]

例子3——跨进程传递消息

除了在线程间使用外,Handler还可以通过IMessenger和Message来实现进程间的消息传递。
因为Message本身实现了Parcelable接口支持跨进程,Handler中定义了继承IMessenger.Stub的MessengerImpl类作为跨进程传入Message的入口。进程外通过Handler.getIMessenger()方法获得此Handler的IMessenger即可向它发送消息。

Handler.javaIMessenger mMessenger;final IMessenger getIMessenger() {    synchronized (mQueue) {        if (mMessenger != null) {            return mMessenger;    }    mMessenger = new MessengerImpl();    return mMessenger;   }}private final class MessengerImpl extends IMessenger.Stub {    public void send(Message msg) {        msg.sendingUid = Binder.getCallingUid();        Handler.this.sendMessage(msg);    }}

Android framework中实现了一个叫AsyncChannel的类,利用Handler夸进程特性,支持2个进程间的Handler互通消息,有兴趣可以看一下:
/frameworks/base/core/java/com/android/internal/util/AsyncChannel.java

第四个问题

例子1中,Looper.prepare()Looper.loop()方法调用顺序是固定的,必须在handler创建前执行Looper.prepare(),在Handler创建后执行Looper.loop(),这样Handler才能正常运行在线程中。
但例子2中并没有看到Looper的身影,这是为什么?

第四个问题:
Looper是什么?为什么例子中2个Looper方法要按这样的顺序调用?


Handler和Looper的关系

通过第一个例子可以猜测,Looper应该就是维护消息循环的地方,且Handler的构造方法中一定有某些东西关联到Looper,于是先从Handler的构造方法入手。

Handler构造方法

Handler有6个有参构造方法,另外还有1个个无参构造方法:
这里写图片描述

这是其中一个Handler的有参构造方法,保存了Looper,MessageQueue等实例,可以说明Handler是直接依赖于Looper的

Handler.javafinal Looper mLooper;final MessageQueue mQueue;final Callback mCallback;final boolean mAsynchronous;public Handler(Looper looper, Callback callback, boolean async) {    mLooper = looper;    mQueue = looper.mQueue;    mCallback = callback;    mAsynchronous = async;}

而Handler无参构造方法内部调用了另一个有参构造方法,最后在该方法中还是通过Looper.myLooper()方法获取到了Looper实例:

Handler.javapublic Handler() {    this(null, false);}public Handler(Callback callback, boolean async) {    //实际上还是获取到了Looper    mLooper = Looper.myLooper();    if (mLooper == null) {        throw new RuntimeException(                "Can't create handler inside thread that has not called Looper.prepare()");    }    mQueue = mLooper.mQueue;    mCallback = callback;    mAsynchronous = async;}

Looper.myLooper()方法中调用ThreadLocal.get()返回一个Looper实例:

Looper.javapublic static @Nullable Looper myLooper() {    return sThreadLocal.get();}

既然能get到一个Looper,那么继续寻找sThreadLocal在何处去set这个Looper。
结果找上了Looper.prepare()方法:

Looper.javastatic final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();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));}//唯一构造方法是private的,创建了MessageQueue,并保存了当前的Thread实例private Looper(boolean quitAllowed) {    mQueue = new MessageQueue(quitAllowed);//创建MessageQueue,参数指定了这个queue是否能被退出    mThread = Thread.currentThread();//本线程}

Looper.prepare()内部新建了Looper实例,并set到sThreadLocal,那么,就足以解释为什么在new Handler()之前必须调用Looper.prepare()

——因为Handler需要获取到Looper实例,而Looper.prepare()就是创建Looper的地方。


那么Looper.loop()为什么要在最后执行呢?

Looper.javapublic static void loop() {        final Looper me = myLooper();        final MessageQueue queue = me.mQueue;        ...        for (;;) {            //获取下一个消息            Message msg = queue.next(); // might block            if (msg == null) {                 //退出循环                return;            }            try {                //向Handler分发消息                msg.target.dispatchMessage(msg);            } finally {                ...            }            // Make sure that during the course of dispatching the            // identity of the thread wasn't corrupted.            final long newIdent = Binder.clearCallingIdentity();            msg.recycleUnchecked();        }    }

明显Looper.loop()方法内部是个死循环,循环从MessageQueue中获取消息并分发给Handler,因此loop()方法必须是最后执行的。


最后,来看为什么第二个例子中,主线程创建Handler时不用显式地初始化Looper?
根据上面2个问题的答案思考下,Handler初始化是必须获得Looper的,而Looper只有在Looper.prepare()方法中创建。顺藤摸瓜,在Looper.java中找到了一个叫prepareMainLooper的方法,不仅创建了Looper对象,而且将它保存到了sMainLooper变量中。

Looper.java    private static Looper sMainLooper;  //主线程的Looper    public static void prepareMainLooper() {        prepare(false);//新建Looper,指定        synchronized (Looper.class) {            if (sMainLooper != null) {                throw new IllegalStateException("The main Looper has already been prepared.");            }            //复值到sMainLooper            sMainLooper = myLooper();        }    }    //quitAllowed参数指定了MessageQueue是否允许退出    private Looper(boolean quitAllowed) {        mQueue = new MessageQueue(quitAllowed);        mThread = Thread.currentThread();    }

搜索下Looper.prepareMainLooper()的调用者,竟然是ActivityThread.main()方法。就是说,在Activity创建的时候,主线程创建了自己的main looper,并同样地开启了无限循环模式!这侧面映证了Android应用运行是靠消息驱动的。

ActivityThread.javapublic static void main(String[] args) {        ...        Process.setArgV0("<pre-initialized>");        //创建主线程Looper        Looper.prepareMainLooper();        ActivityThread thread = new ActivityThread();        thread.attach(false);        if (sMainThreadHandler == null) {            sMainThreadHandler = thread.getHandler();        }        //主线程的Event loop开始循环        Looper.loop();        throw new RuntimeException("Main thread loop unexpectedly exited");    }

本章小结

至此,前面提出的4个大问题已经解决了3个:

1. Handler如何与Thread关联?
——这里需要加入Looper的概念。
Handler在线程中创建时获取到looper实例,而Looper在线程中运行消息循环,并分发给Handler。

另外:Looper的消息循环是死循环,因此一个Thread中只能运行一个Looper。而Handler作为消息的发送和处理者,与Looper的关系是多对一的。
因此它们3者的关系是: 1 Looper - 1 Thread - N Handler
这里写图片描述

2. Thread和MessageQueue的关系是?
——MessageQueue在Thread对应的Looper中创建,用于存储消息,消息最后会分发给Handler处理。

  1. MessageQueue如何运作?它如何管理Runnable和Message?
    ——待下一章分析

4. Looper是什么?为什么例子中2个Looper方法要按固定的顺序调用?
分为3个小问题:
当Handler被定义在子线程中时,为什么在new Handler之前必须先Looper.prepare()
——因为Handler需要获取到Looper实例,而Looper.prepare()就是创建Looper的地方。

为什么Looper.loop()要最后执行?
——因为内部实现了一个死循环,用作消息的读取和分发,在Looper.quit()被调用之前,loop循环会一直进行。

在主线程中实现的Handler,为什么无需显式地调用Looper的初始化方法?
——Activity主线程启动时,已经创建好了Looper,我们在Activity中新建的Handler默认绑定这个主线程Looper。

接下来深入分析流程。


消息发送及分发流程

接下来具体讨论消息如何插入,以及如何分发。

Message的组成和消息池

首先来了解下Message是什么。
通过文章开头的类图可以看到,Message是一个数据类,包含用户定义的数据,Runnable实例,关联的Handler。
同时,下一个Message的实例保存在next变量中,可见Message将以链的形式保存。

    //相当于消息的ID,用于在处理时识别消息    public int what;    //arg1和arg2用于存储int类型的数据    public int arg1;     public int arg2;    //保存Object类型的参数,如果在跨进程使用时只支持framework实现的可跨进程的对象    public Object obj;    //保存Bundle形式的数据参数    /*package*/ Bundle data;    //Messenger形式的消息接受者    public Messenger replyTo;    //关联的Handler(消息接收者)    /*package*/ Handler target;    //将被执行的runnable    /*package*/ Runnable callback;    //下一个消息    /*package*/ Message next;    //消息池,Message的重用管理,通过obtain()方法获取可重用的消息    private static Message sPool;

Message中还实现了消息重用,如果使用Message.obtain()方法获取Message,将返回可重用的Message。

    private static Message sPool;    public static Message obtain() {        synchronized (sPoolSync) {            //如果pool中有可重用的message则直接返回            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();    }    //Looper.loop()处理完一个消息后,会调用此方法去“回收”Message实例    //实际上Message将被重置并放入“消息池”中。    void recycleUnchecked() {        flags = FLAG_IN_USE;        what = 0;        arg1 = 0;        arg2 = 0;        obj = null;        replyTo = null;        sendingUid = -1;        when = 0;        target = null;        callback = null;        data = null;        synchronized (sPoolSync) {            if (sPoolSize < MAX_POOL_SIZE) {                next = sPool;                sPool = this;                sPoolSize++;            }        }    }

Looper中的消息循环和消息分发

正如前文看到Looper.loop()开启了一个死循环,从MessageQueue的next方法获取消息后,分发给Handler处理。这里先快速地看下消息如何分发,然后来重点看MessageQueue的next方法。

Looper.java/**     * Run the message queue in this thread. Be sure to call     * {@link #quit()} to end the loop.     */    public static void loop() {        final Looper me = myLooper();        ...        final MessageQueue queue = me.mQueue;        ...        for (;;) {            //获取下一个Message,没有消息时可能会阻塞            Message msg = queue.next(); // might block            ...            try {                //执行runnable,或者分发消息给handleMessage()或callback                msg.target.dispatchMessage(msg);            } finally {            }            ...            msg.recycleUnchecked();        }    }

循环从MessageQueue.next()中获取消息,这里先来看消息的分发:Handler.dispatchMessage()
1. 如果通过post(Runnable)发送的Message,那么只执行Runnable.run()。
2. 如果如果实现了Handler.Callback接口,则消息分发给Callback.handleMessage()方法处理,返回ture就不会执行第三步
3. 由Handler.handleMessage()处理

    /**     * Handle system messages here.     */    public void dispatchMessage(Message msg) {        if (msg.callback != null) {            //执行runnable            handleCallback(msg);        } else {            if (mCallback != null) {                //分发给Handler.Callback处理                //如果实现了Handler.Callback接口,则消息可以在这里被处理                //如果执行完Callback.handleMessage后返回true,则不再分发给Handler.handleMessage()处理                if (mCallback.handleMessage(msg)) {                    return;                }            }            //直接在handleMessage中处理            handleMessage(msg);        }    }    private static void handleCallback(Message message) {        message.callback.run();    }    public interface Callback {        public boolean handleMessage(Message msg);    }    /**     * Subclasses must implement this to receive messages.     */    public void handleMessage(Message msg) {    }

获取消息:MessageQueue.next()方法

MessageQueue的next方法也是一个循环,主要目的是获取下一个要被处理的Message,其中的几个要点:
1. nativePollOnce是阻塞的,中间执行了epoll_wait等待,通过nativeWake主动唤醒或者到达超时时间后唤醒。
2. 如果插入了SyncBarrier消息(handler为null的消息),则只会处理“异步”的消息(设置了Asynchronous flag的消息,详看后文)
3. 如果当前消息没有到达when设定的时间,则会重新进入nativePollOnce,设置具体的超时时间
4. 到达设定时间的Message会被返回,由Looper分发处理。
5. 如果进入next()时没有消息要被马上处理,则会执行IdleHandler的处理。

Message next() {        final long ptr = mPtr;        ...        int pendingIdleHandlerCount = -1; // -1 only during first iteration        int nextPollTimeoutMillis = 0;        for (;;) {            ...            //没有消息需要被处理时会阻塞            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;                //msg.target == null则该消息为SyncBarrier消息                //排在SyncBarrier之后的Message中,只有设置了Asynchronous的Message会被处理                //SyncBarrier的概念需要展开来讲。                if (msg != null && msg.target == null) {                    do {                        prevMsg = msg;                        msg = msg.next;                    } while (msg != null && !msg.isAsynchronous());                }                if (msg != null) {                    //消息设置了delay时间(when是将来执行的时间)。                    //还没到时间去处理,计算nextPollTimeoutMillis值,由nativePollOnce决定唤醒阻塞的时间                    if (now < msg.when) {                        nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);                    } else {                        //返回需要被处理的消息,并删除链节点                        mBlocked = false;                        if (prevMsg != null) {                            prevMsg.next = msg.next;                        } else {                            mMessages = msg.next;                        }                        msg.next = null;                        msg.markInUse();                        return msg;                    }                } else {                    //没有任何消息,nextPollTimeoutMillis置成-1                    nextPollTimeoutMillis = -1;                }                //quit()被调用后,退出循环                if (mQuitting) {                    dispose();                    return null;                }                //获取IdleHandler——列表中没有消息或者正等待超时期间会通知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.                    mBlocked = true;                    continue;                }                if (mPendingIdleHandlers == null) {                    mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];                }                mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);            }            //执行IdleHandler.queueIdle()            //只有当第一次循环没有返回Message时执行,就是说当前所有Message已经处理完            //或者还没到时间处理的时候。            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 {                    //通过返回值决定IdleHandler是否保留                    keep = idler.queueIdle();                } catch (Throwable t) {                    Log.wtf(TAG, "IdleHandler threw exception", t);                }                if (!keep) {                    synchronized (this) {                        mIdleHandlers.remove(idler);                    }                }            }            //不再执行IdleHandler.queueIdle()            pendingIdleHandlerCount = 0;            //执行IdleHandler期间可能有消息插入,因此回头需要马上唤醒nativePollOnce            nextPollTimeoutMillis = 0;        }    }

忽略IdleHandler和nextPollTimeoutMillis值的影响,大概流程如下:
这里写图片描述

nativePollOnce

nativePollOnce名字上理解应该是轮询一次的意思,代码如下:
android_os_MessageQueue.cpp在nativePollOnce方法中,调用了Looper的pollOnce方法:

/frameworks/base/core/jni/android_os_MessageQueue.cppstatic 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;    }}

流程进入到Looper,那么先来从头了解下它。

Native looper

在java层初始化MessageQueue的时候调用了nativeInit():

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

nativeInit()初始化了NativeMessageQueue和Looper:

android_os_MessageQueue.cppstatic jlong android_os_MessageQueue_nativeInit(JNIEnv* env, jclass clazz) {    //创建NativeMessageQueue    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) {        //创建looper        mLooper = new Looper(false);        Looper::setForThread(mLooper);    }}

在Looper的构造函数中调用了rebuildEpollLocked():
1)初始化了epoll实例mEpollFd;
2)注册fd监听——mWakeEventFd。

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.    if (mEpollFd >= 0) {        close(mEpollFd);    }    //初始化了epoll实例    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;    //注册fd用于唤醒——mWakeEventFd    int result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeEventFd, & eventItem);    //注册其他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);        ...    }}

马上回到pollOnce函数,它调用的pollInner函数中执行了epoll_wait,等待mWakeEventFd和其他注册的fd被唤醒,然后分发Native消息,等到函数返回后,Java层的MessageQueue.next()才继续执行。

/system/core/libutils/Looper.cppint Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) {    ...    result = pollInner(timeoutMillis);}int Looper::pollInner(int timeoutMillis) {    //调整timeout时间    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;        }    }    ...    //epoll_wait,等待唤醒或超时    struct epoll_event eventItems[EPOLL_MAX_EVENTS];    int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);    ...    for (int i = 0; i < eventCount; i++) {        int fd = eventItems[i].data.fd;        uint32_t epollEvents = eventItems[i].events;        if (fd == mWakeEventFd) {            if (epollEvents & EPOLLIN) {                //清空mWakeEventFd管道                awoken();            } else {                ALOGW("Ignoring unexpected epoll events 0x%x on wake event fd.", epollEvents);            }        } else {            ...        }    }Done: ;    //Native层消息的分发    ...    return result;}//清空mWakeEventFd管道void Looper::awoken() {    uint64_t counter;    TEMP_FAILURE_RETRY(read(mWakeEventFd, &counter, sizeof(uint64_t)));}

那么唤醒这个epoll_wait的地方在哪?

nativeWake

android_os_MessageQueue.cpp的nativeWake函数,调用了Looper.cpp的wake()函数,向mWakeEventFd管道写入了数据,epoll_wait被唤醒。

Looper.cppvoid Looper::wake() {    uint64_t inc = 1;    //向mWakeEventFd管道写入数据    ssize_t nWrite = TEMP_FAILURE_RETRY(write(mWakeEventFd, &inc, sizeof(uint64_t)));    ...}

那么问题又来了,何时去唤醒这个epoll? 答案在java层插入新消息时,调用的MessageQueue.enqueueMessage()

插入新的Message

Handler通过post和sendMessage方法向MessageQueue发送Runnable或者Message,实际上最后都会被封装成Message,通过MessageQueue.enqueueMessage()方法加入到消息链表。

Handler.javaprivate boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {        msg.target = this;        if (mAsynchronous) {            msg.setAsynchronous(true);        }        return queue.enqueueMessage(msg, uptimeMillis);}

MessageQueue.enqueueMessage方法接收新的消息,通过消息延迟的时间将其插入到正确的位置。

MessageQueue.javaMessage mMessages;boolean enqueueMessage(Message msg, long when) {        ...        synchronized (this) {            if (mQuitting) {                msg.recycle();                return false;            }            msg.markInUse();            msg.when = when;            Message p = mMessages;            boolean needWake;            if (p == null || when == 0 || when < p.when) {                //新消息作为链表头                msg.next = p;                mMessages = msg;                needWake = mBlocked;            } else {                //如果找到sync barrier,且当前消息是“异步”的,那么需要重新调整唤醒时间                needWake = mBlocked && p.target == null && msg.isAsynchronous();                Message prev;                //按照when取值将Message插入对应的位置                for (;;) {                    prev = p;                    p = p.next;                    if (p == null || when < p.when) {                        break;                    }                    //下一个是没有设置handler的“异步”消息,无需唤醒native looper                    if (needWake && p.isAsynchronous()) {                        needWake = false;                    }                }                msg.next = p; // invariant: p == prev.next                prev.next = msg;            }            //唤醒native looper            if (needWake) {                nativeWake(mPtr);            }        }        return true;    }

插入消息后,有条件地执行nativeWake去唤醒epoll。needWake的值依赖mBlocked——当进入next()方法时没有待处理的消息,mBlock为true,有消息并返回到looper时,mBlock为false。

结合next()和enqueueMessage()方法,得知nativeWake被调用的条件为:
1. next()方法在等待新消息,且新插入消息的为链表头时。needWake为true
2. 设置了Sync Barrier,且插入的消息是“异步”的。needWake为true

核心流程大概分析完成:
1. java层的looper循环调用MessageQueue.next()获取下一个消息来处理;
2. next()方法进入native层nativePollOnce方法,Looper.cpp进入epoll_wait等待fd被唤醒
3. Handler向MessageQueue插入消息后,有条件地唤醒native looper,使next()方法返回
4. Looper在获取到新消息后分发处理。

关于SyncBarrier

首先,Message中有“同步”和“异步”的概念(貌似实际上只是个状态的区分,主要作用时配合SyncBarrier,并没有同步性上的区别),使用setAsynchronous方法设置:

Message.java    public void setAsynchronous(boolean async) {        if (async) {            flags |= FLAG_ASYNCHRONOUS;        } else {            flags &= ~FLAG_ASYNCHRONOUS;        }    }

而通过postSyncBarrier()方法,可以发送一个synchronization barrier(就直译称为“同步栏”吧)到Message链表中,用来暂停在同步栏之后发送的“同步”消息的处理,此时只有“异步”的消息能被继续处理。 设置同步栏后必须在条件准备好后移除它(调用removeSyncBarrier()方法)。

这个机制的作用在于可以马上暂停执行“同步”消息,直到条件允许后通过移除同步栏来恢复“同步”消息的处理。例如在View.invalidate需要执行时,将会设置同步栏挂起所有“同步”消息,直到下一帧准备好显示后移除同步栏。

而设置“异步”消息则可以免受同步栏的影响,用于接收输入等需要持续的工作,具体如下面这段注释:
/**
* Asynchronous messages are exempt from synchronization barriers. They typically
* represent interrupts, input events, and other signals that must be handled
* independently even while other work has been suspended.
* */
工作流程大致如图:
这里写图片描述

设置同步栏就是插入一个不指定handler的Message,通过一个token值来标记:

MessageQueue.java    /**     * @hide     */    //设置同步栏    //postSyncBarrier不是公开的API,只供系统内部调用    public int postSyncBarrier() {        return postSyncBarrier(SystemClock.uptimeMillis());    }    private int postSyncBarrier(long when) {        synchronized (this) {            final int token = mNextBarrierToken++;            //消息没有设置handler,以此来识别这是个sync barrier            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;        }    }

移除同步栏时通过token值匹配并删除该Message:

    /**     * @hide     */    //移除同步栏同样是hide的方法    public void removeSyncBarrier(int token) {        // Remove a sync barrier token from the queue.        // If the queue is no longer stalled by a barrier then wake it.        synchronized (this) {            Message prev = null;            Message p = mMessages;            while (p != null && (p.target != null || p.arg1 != token)) {                prev = p;                p = p.next;            }            if (p == null) {                throw new IllegalStateException("The specified message queue synchronization "                        + " barrier token has not been posted or has already been removed.");            }            final boolean needWake;            if (prev != null) {                prev.next = p.next;                needWake = false;            } else {                mMessages = p.next;                needWake = mMessages == null || mMessages.target != null;            }            p.recycleUnchecked();            // If the loop is quitting then it is already awake.            // We can assume mPtr != 0 when mQuitting is false.            if (needWake && !mQuitting) {                nativeWake(mPtr);            }        }    }

关于IdleHandler

  1. 只有当前所有Message已经处理完或者待处理的Message还没到时间处理的时候,才会执行IdleHandler处理一次
  2. 使用IdleHandler必须定义实现了IdleHandler接口的类,并在queueIdle()定义需要执行的操作(通常是释放资源),返回值决定这个Handler是否一直保留,并在将来空闲时再次执行。
  3. 通过MessageQueue.addIdleHandler 添加IdleHandler
MessageQueue.java    private final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<IdleHandler>();    private SparseArray<FileDescriptorRecord> mFileDescriptorRecords;    private IdleHandler[] mPendingIdleHandlers;    public static interface IdleHandler {        boolean queueIdle();    }    public void addIdleHandler(@NonNull IdleHandler handler) {        if (handler == null) {            throw new NullPointerException("Can't add a null IdleHandler");        }        synchronized (this) {            mIdleHandlers.add(handler);        }    }

一个例子:
ActivityThread中定义了一个IdleHandler,用于执行GC回收垃圾:

ActivityThread.java    final class GcIdler implements MessageQueue.IdleHandler {        @Override        public final boolean queueIdle() {            doGcIfNeeded();            return false;        }    }

END

写得有点杂乱,以后有时间再来优化下。
在分析过程中,参考了下面几篇文章,写的比较清晰易懂:
《聊一聊Android的消息机制》
《Looper中的睡眠等待与唤醒机制》