android下的线程,Looper线程,MessageQueue,Handler,Message等之间的关系,以及Message的send/post及Message dispatch的过程。
Looper线程
我们知道,线程是进程中某个单一顺序的控制流,它是内核做CPU调度的单位。那何为Looper线程呢?所谓Looper线程,即是借助于Looper和MessageQueue来管理控制流的一类线程。在android系统中,application的主线程即是借助于Looper和MessageQueue来管理控制流的。其实,不仅仅只有主线程可以用Looper和MessageQueue来管理控制流,其他的线程也一样可以。我们可以先看一下android source code的注释中给出的一种Looper线程的实现方式:
01 | package com.example.messagequeuedemo; |
03 | import android.os.Handler; |
04 | import android.os.Looper; |
05 | import android.util.Log; |
07 | public class LooperThread extends Thread { |
08 | public static final String TAG = MainActivity.TAG; |
09 | private static final String CompTAG = "<span></span>LooperThread<span></span>" ; |
11 | public Handler mHandler; |
15 | Log.d(TAG, CompTAG + ": LooperThread=>run" ); |
18 | mHandler = new Handler() { |
19 | public void handleMessage(android.os.Message msg) { |
20 | Log.d(TAG, CompTAG + ": LooperThread=>Handler=>handleMessage" ); |
可以看到,就是在线程的run()方法中,调用Looper.prepare()做一些初始化,然后创建一个Handler对象,最后执行Looper.loop()即开始了整个的事件循环。就是这么的简单,一个可以使用消息队列来管理线程执行流程的Looper 线程就创建好了。
接着我们来看一下,神秘的Looper.prepare()到底都干了些什么事情:
02 | static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(); |
04 | /** Initialize the current thread as a looper. |
05 | * This gives you a chance to create handlers that then reference |
06 | * this looper, before actually starting the loop. Be sure to call |
07 | * {@link #loop()} after calling this method, and end it by calling |
10 | public static void prepare() { |
14 | private static void prepare( boolean quitAllowed) { |
15 | if (sThreadLocal.get() != null ) { |
16 | throw new RuntimeException( "Only one Looper may be created per thread" ); |
18 | sThreadLocal.set( new Looper(quitAllowed)); |
22 | private Looper( boolean quitAllowed) { |
23 | mQueue = new MessageQueue(quitAllowed); |
25 | mThread = Thread.currentThread(); |
可以看到,它做的事情就是为当前的线程创建了一个Looper对象,并存储在一个静态的线程局部变量中。在Looper的构造函数中创建了MessageQueue,同时Looper会引用到当前的线程,并将一个表示状态的变量mRun设置为true。对于此处的线程局部变量sThreadLocal,可以理解为就是一个HashMap,该HashMap中存放的数据其类型为Looper,而HashMap的key则Thread.currentThread()。
启动Looper线程就和启动普通的线程一样,比如:
01 | public class MainActivity extends Activity { |
02 | public static final String TAG = "MessageQueueDemo" ; |
03 | private static final String CompTAG = "MainActivity" ; |
04 | private LooperThread mLooperThread; |
07 | protected void onCreate(Bundle savedInstanceState) { |
08 | Log.d(TAG, CompTAG + ": MainActivity=>onCreate" ); |
09 | super .onCreate(savedInstanceState); |
10 | setContentView(R.layout.activity_main); |
12 | mLooperThread = new LooperThread(); |
13 | mLooperThread.start(); |
同样是new一个Thread对象,然后执行该对象的start()方法。
其实Looper线程有两种,一种就是我们上面看到的那种普通的Looper线程,另外一种则是main loop线程,创建前者使用我们前面看到的Looper.prepare()方法,而要创建后者,我们则可以使用Looper.prepareMainLooper()方法。可以看一下Looper.prepareMainLooper()的实现:
02 | * Initialize the current thread as a looper, marking it as an |
03 | * application's main looper. The main looper for your application |
04 | * is created by the Android environment, so you should never need |
05 | * to call this function yourself. See also: {@link #prepare()} |
07 | public static void prepareMainLooper() { |
09 | synchronized (Looper. class ) { |
10 | if (sMainLooper != null ) { |
11 | throw new IllegalStateException( "The main Looper has already been prepared." ); |
13 | sMainLooper = myLooper(); |
比较特别的地方即在于,此处调用prepare()方法传进去的参数为false,即表示这个Looper不能够被quit掉。其他倒是基本一样。整个android系统中,调用到prepareMainLooper()方法的大概有两处:
1 | /frameworks/base/services/java/com/android/server/ |
2 | H A D SystemServer.java 94 Looper.prepareMainLooper(); |
3 | /frameworks/base/core/java/android/app/ |
4 | H A D ActivityThread.java 5087 Looper.prepareMainLooper(); |
一处在ServerThread的run()方法中,用于为system server主线程初始化消息队列等,另外一处在ActivityThread的run()方法中,自然即是创建android app主线程的消息队列了。
通过消息与Looper线程交互
那Looper线程的特别之处究竟在哪里呢?如前所述,这种线程有一个Looper与之关联,这种线程会使用消息队列,或者称为事件循环来管理执行的流程。那这种特别之处又如何体现呢?其他线程可以向此类线程中丢消息进来,当然此类线程本身也可以往自己的消息队列里面丢消息,然后在事件循环中,这种事件会得到有效的处理。那究竟要如何往Looper线程的消息队列中发送消息呢?
回忆我们前面创建Looper线程的那个code,我们不是有创建出来一个Handler嘛。没错,我们就是通过Handler来向Looper线程的MessageQueue中发送消息的。可以看一下code的写法。先是LooperThread的写法:
01 | package com.intel.helloworld; |
03 | import android.os.Handler; |
04 | import android.os.Looper; |
05 | import android.os.Message; |
06 | import android.util.Log; |
08 | public class LooperThread extends Thread { |
09 | private static final String TAG = MainActivity.TAG; |
10 | private static final String CompTAG = "LooperThread" ; |
11 | public Handler mHandler; |
15 | Log.d(TAG, CompTAG + ": " + "LooperThread-->run" ); |
18 | mHandler = new Handler() { |
20 | public void handleMessage(Message msg) { |
22 | Log.d(TAG, CompTAG + ": " + "Handler-->handleMessage, msg.what = " + msg.what); |
29 | public Handler getHandler() { |
然后是向Looper线程发送消息的部分的写法:
01 | package com.intel.helloworld; |
03 | import android.os.Bundle; |
04 | import android.os.Handler; |
05 | import android.os.Message; |
06 | import android.app.Activity; |
07 | import android.util.Log; |
08 | import android.view.Menu; |
10 | public class MainActivity extends Activity { |
11 | public static final String TAG = "LifecycleDemoApp" ; |
12 | private static final String CompTAG = "MainActivity" ; |
14 | public static final int MESSAGE_WHAT_CREATE = 1 ; |
15 | public static final int MESSAGE_WHAT_START = 2 ; |
16 | public static final int MESSAGE_WHAT_RESUME = 3 ; |
17 | public static final int MESSAGE_WHAT_PAUSE = 4 ; |
18 | public static final int MESSAGE_WHAT_STOP = 5 ; |
19 | public static final int MESSAGE_WHAT_DESTROY = 6 ; |
24 | protected void onCreate(Bundle savedInstanceState) { |
25 | Log.d(TAG, CompTAG + ": " + "Activity-->onCreate" ); |
26 | super .onCreate(savedInstanceState); |
27 | setContentView(R.layout.activity_main); |
29 | mThread = new LooperThread(); |
34 | protected void onStart() { |
35 | Log.d(TAG, CompTAG + ": " + "Activity-->onStart" ); |
38 | Handler handler = mThread.mHandler; |
39 | Message msg = Message.obtain(); |
40 | msg.what = MESSAGE_WHAT_START; |
41 | handler.sendMessage(msg); |
45 | protected void onResume() { |
46 | Log.d(TAG, CompTAG + ": " + "Activity-->onResume" ); |
49 | Handler handler = mThread.mHandler; |
50 | Message msg = Message.obtain(); |
51 | msg.what = MESSAGE_WHAT_RESUME; |
52 | handler.sendMessage(msg); |
56 | protected void onPause() { |
57 | Log.d(TAG, CompTAG + ": " + "Activity-->onPause" ); |
60 | Handler handler = mThread.mHandler; |
61 | Message msg = Message.obtain(); |
62 | msg.what = MESSAGE_WHAT_PAUSE; |
63 | handler.sendMessage(msg); |
67 | protected void onStop() { |
68 | Log.d(TAG, CompTAG + ": " + "Activity-->onStop" ); |
71 | Handler handler = mThread.mHandler; |
72 | Message msg = Message.obtain(); |
73 | msg.what = MESSAGE_WHAT_STOP; |
74 | handler.sendMessage(msg); |
78 | protected void onDestroy() { |
79 | Log.d(TAG, CompTAG + ": " + "Activity-->onDestroy" ); |
82 | Handler handler = mThread.mHandler; |
83 | Message msg = Message.obtain(); |
84 | msg.what = MESSAGE_WHAT_DESTROY; |
85 | handler.sendMessage(msg); |
88 | @Override <span style= "color: rgb(229, 51, 51);" ></span> public boolean onCreateOptionsMenu(Menu menu) { |
90 | getMenuInflater().inflate(R.menu.main, menu); |
95 | protected void onSaveInstanceState(Bundle outState) { |
96 | Log.d(TAG, CompTAG + ": " + "Activity-->onSaveInstanceState" ); |
97 | super .onSaveInstanceState(outState); |
向一个Looper线程发送消息的过程,基本上即是,调用Message.obtain()或Handler.obtainMessage()获取一个Message对象->设置Message->调用 Looper线程中创建的Handler对象来发送消息。
Handler究竟是如何知道要向哪个MessageQueue中发送消息呢,从前面的code中,我们找不到任何将Handler与特定的MessageQueue关联起来的代码,这究竟是怎么回事呢?这也是我们强调要使用Looper线程中创建的Handler对象来向该Looper线程中发送消息的原因。我们可以看一下Handler对象构造的过程:
002 | * Default constructor associates this handler with the {@link Looper} for the |
005 | * If this thread does not have a looper, this handler won't be able to receive messages |
006 | * so an exception is thrown. |
013 | * Constructor associates this handler with the {@link Looper} for the |
014 | * current thread and takes a callback interface in which you can handle |
017 | * If this thread does not have a looper, this handler won't be able to receive messages |
018 | * so an exception is thrown. |
020 | * @param callback The callback interface in which to handle messages, or null. |
022 | public Handler(Callback callback) { |
023 | this (callback, false ); |
027 | * Use the provided {@link Looper} instead of the default one. |
029 | * @param looper The looper, must not be null. |
031 | public Handler(Looper looper) { |
032 | this (looper, null , false ); |
036 | * Use the provided {@link Looper} instead of the default one and take a callback |
037 | * interface in which to handle messages. |
039 | * @param looper The looper, must not be null. |
040 | * @param callback The callback interface in which to handle messages, or null. |
042 | public Handler(Looper looper, Callback callback) { |
043 | this (looper, callback, false ); |
047 | * Use the {@link Looper} for the current thread |
048 | * and set whether the handler should be asynchronous. |
050 | * Handlers are synchronous by default unless this constructor is used to make |
051 | * one that is strictly asynchronous. |
053 | * Asynchronous messages represent interrupts or events that do not require global ordering |
054 | * with represent to synchronous messages. Asynchronous messages are not subject to |
055 | * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier long)}. |
057 | * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for |
058 | * each {@link Message} that is sent to it or {@link Runnable} that is posted to it. |
062 | public Handler( boolean async) { |
067 | * Use the {@link Looper} for the current thread with the specified callback interface |
068 | * and set whether the handler should be asynchronous. |
070 | * Handlers are synchronous by default unless this constructor is used to make |
071 | * one that is strictly asynchronous. |
073 | * Asynchronous messages represent interrupts or events that do not require global ordering |
074 | * with represent to synchronous messages. Asynchronous messages are not subject to |
075 | * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier long)}. |
077 | * @param callback The callback interface in which to handle messages, or null. |
078 | * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for |
079 | * each {@link Message} that is sent to it or {@link Runnable} that is posted to it. |
083 | public Handler(Callback callback, boolean async) { |
084 | if (FIND_POTENTIAL_LEAKS) { |
085 | final Class<? extends Handler> klass = getClass(); |
086 | if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) && |
087 | (klass.getModifiers() & Modifier.STATIC) == 0 ) { |
088 | Log.w(TAG, "The following Handler class should be static or leaks might occur: " + |
089 | klass.getCanonicalName()); |
093 | mLooper = Looper.myLooper(); |
094 | if (mLooper == null ) { |
095 | throw new RuntimeException( |
096 | "Can't create handler inside thread that has not called Looper.prepare()" ); |
098 | mQueue = mLooper.mQueue; |
099 | mCallback = callback; |
100 | mAsynchronous = async; |
可以看到,很简单,是通过Looper.myLooper()获取到当前线程的Looper对象,并与相关的MessageQueue等关联起来的。这也是前面我们在实现Looper线程时,要在其run方法中创建一个public的Handler的依据。当然,我们也可以在构造Handler对象时,显式地使其与特定的Looper对象关联起来。
Handler提供了两组函数用于向一个Looper线程的MessageQueue中发送消息,分别是postXXX()族和sendXXX()族。可以先看一下sendXXX()族的实现:
002 | * Pushes a message onto the end of the message queue after all pending messages |
003 | * before the current time. It will be received in {@link #handleMessage}, |
004 | * in the thread attached to this handler. |
006 | * @return Returns true if the message was successfully placed in to the |
007 | * message queue. Returns false on failure, usually because the |
008 | * looper processing the message queue is exiting. |
010 | public final boolean sendMessage(Message msg) |
012 | return sendMessageDelayed(msg, 0 ); |
016 | * Sends a Message containing only the what value. |
018 | * @return Returns true if the message was successfully placed in to the |
019 | * message queue. Returns false on failure, usually because the |
020 | * looper processing the message queue is exiting. |
022 | public final boolean sendEmptyMessage( int what) |
024 | return sendEmptyMessageDelayed(what, 0 ); |
028 | * Sends a Message containing only the what value, to be delivered |
029 | * after the specified amount of time elapses. |
030 | * @see #sendMessageDelayed(android.os.Message, long) |
032 | * @return Returns true if the message was successfully placed in to the |
033 | * message queue. Returns false on failure, usually because the |
034 | * looper processing the message queue is exiting. |
036 | public final boolean sendEmptyMessageDelayed( int what, long delayMillis) { |
037 | Message msg = Message.obtain(); |
039 | return sendMessageDelayed(msg, delayMillis); |
043 | * Sends a Message containing only the what value, to be delivered |
044 | * at a specific time. |
045 | * @see #sendMessageAtTime(android.os.Message, long) |
047 | * @return Returns true if the message was successfully placed in to the |
048 | * message queue. Returns false on failure, usually because the |
049 | * looper processing the message queue is exiting. |
052 | public final boolean sendEmptyMessageAtTime( int what, long uptimeMillis) { |
053 | Message msg = Message.obtain(); |
055 | return sendMessageAtTime(msg, uptimeMillis); |
059 | * Enqueue a message into the message queue after all pending messages |
060 | * before (current time + delayMillis). You will receive it in |
061 | * {@link #handleMessage}, in the thread attached to this handler. |
063 | * @return Returns true if the message was successfully placed in to the |
064 | * message queue. Returns false on failure, usually because the |
065 | * looper processing the message queue is exiting. Note that a |
066 | * result of true does not mean the message will be processed -- if |
067 | * the looper is quit before the delivery time of the message |
068 | * occurs then the message will be dropped. |
070 | public final boolean sendMessageDelayed(Message msg, long delayMillis) |
072 | if (delayMillis < 0 ) { |
075 | return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); |
079 | * Enqueue a message into the message queue after all pending messages |
080 | * before the absolute time (in milliseconds) <var>uptimeMillis</var>. |
081 | * <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b> |
082 | * You will receive it in {@link #handleMessage}, in the thread attached |
085 | * @param uptimeMillis The absolute time at which the message should be |
086 | * delivered, using the |
087 | * {@link android.os.SystemClock#uptimeMillis} time-base. |
089 | * @return Returns true if the message was successfully placed in to the |
090 | * message queue. Returns false on failure, usually because the |
091 | * looper processing the message queue is exiting. Note that a |
092 | * result of true does not mean the message will be processed -- if |
093 | * the looper is quit before the delivery time of the message |
094 | * occurs then the message will be dropped. |
096 | public boolean sendMessageAtTime(Message msg, long uptimeMillis) { |
097 | MessageQueue queue = mQueue; |
099 | RuntimeException e = new RuntimeException( |
100 | this + " sendMessageAtTime() called with no mQueue" ); |
101 | Log.w( "Looper" , e.getMessage(), e); |
104 | return enqueueMessage(queue, msg, uptimeMillis); |
108 | * Enqueue a message at the front of the message queue, to be processed on |
109 | * the next iteration of the message loop. You will receive it in |
110 | * {@link #handleMessage}, in the thread attached to this handler. |
111 | * <b>This method is only for use in very special circumstances -- it |
112 | * can easily starve the message queue, cause ordering problems, or have |
113 | * other unexpected side-effects.</b> |
115 | * @return Returns true if the message was successfully placed in to the |
116 | * message queue. Returns false on failure, usually because the |
117 | * looper processing the message queue is exiting. |
119 | public final boolean sendMessageAtFrontOfQueue(Message msg) { |
120 | MessageQueue queue = mQueue; |
122 | RuntimeException e = new RuntimeException( |
123 | this + " sendMessageAtTime() called with no mQueue" ); |
124 | Log.w( "Looper" , e.getMessage(), e); |
127 | return enqueueMessage(queue, msg, 0 ); |
130 | private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { |
133 | msg.setAsynchronous( true ); |
135 | return queue.enqueueMessage(msg, uptimeMillis); |
绕来绕去,最终都是调用MessageQueue的enqueueMessage()方法来将一个Message放入一个MessageQueue中。值得注意的是,在Handler.enqueueMessage()中,会将Message的target设置为this,这实际上是决定了Looper的消息循环中,在dispatch/handle message时将会使用的Handler。即,在default情况下,处理message的那个handler也将会是发送此message的handler。
Handler实际的职责,并不像它的名称所显示的那样,其实它不仅仅是处理message,它还负责发送Message给线程的MessageQueue。
再来看一下MessageQueue的enqueueMessage()方法的code:
01 | boolean enqueueMessage(Message msg, long when) { |
03 | throw new AndroidRuntimeException(msg + " This message is already in use." ); |
05 | if (msg.target == null ) { |
06 | throw new AndroidRuntimeException( "Message must have a target." ); |
12 | RuntimeException e = new RuntimeException( |
13 | msg.target + " sending message to a Handler on a dead thread" ); |
14 | Log.w( "MessageQueue" , e.getMessage(), e); |
19 | Message p = mMessages; |
20 | if (p == null || when == 0 || when < p.when) { |
29 | needWake = mBlocked && p.target == null && msg.isAsynchronous(); |
34 | if (p == null || when < p.when) { |
37 | if (needWake && p.isAsynchronous()) { |
整个将Message放入MessageQueue的算法也还算比较清晰简洁,并没有什么太绕的地方。此处我们可以一览MessageQueue中保存Messages的结构,即,MessageQueue用一个单向链表来保存所有的Message,而链表中各个Message则按照其请求的执行时间先后来排列。
向Looper 线程的MessageQueue中发送消息的另外一族方法postXXX(),其实现同前面的sendXXX()族方法也大同小异啦:
02 | * Causes the Runnable r to be added to the message queue. |
03 | * The runnable will be run on the thread to which this handler is |
06 | * @param r The Runnable that will be executed. |
08 | * @return Returns true if the Runnable was successfully placed in to the |
09 | * message queue. Returns false on failure, usually because the |
10 | * looper processing the message queue is exiting. |
12 | public final boolean post(Runnable r) |
14 | return sendMessageDelayed(getPostMessage(r), 0 ); |
17 | private static Message getPostMessage(Runnable r) { |
18 | Message m = Message.obtain(); |
Post的message,其callback将是传入的Runnable对象,其他就与send的message一样了。
消息队列中消息的处理
消息队列中的消息是在Looper.loop()中被处理的:
02 | * Run the message queue in this thread. Be sure to call |
03 | * {@link #quit()} to end the loop. |
05 | public static void loop() { |
06 | final Looper me = myLooper(); |
08 | throw new RuntimeException( "No Looper; Looper.prepare() wasn't called on this thread." ); |
10 | final MessageQueue queue = me.mQueue; |
14 | Binder.clearCallingIdentity(); |
15 | final long ident = Binder.clearCallingIdentity(); |
18 | Message msg = queue.next(); |
25 | Printer logging = me.mLogging; |
26 | if (logging != null ) { |
27 | logging.println( ">>>>> Dispatching to " + msg.target + " " + |
28 | msg.callback + ": " + msg.what); |
31 | msg.target.dispatchMessage(msg); |
33 | if (logging != null ) { |
34 | logging.println( "<<<<< Finished to " + msg.target + " " + msg.callback); |
39 | final long newIdent = Binder.clearCallingIdentity(); |
40 | if (ident != newIdent) { |
41 | Log.wtf(TAG, "Thread identity changed from 0x" |
42 | + Long.toHexString(ident) + " to 0x" |
43 | + Long.toHexString(newIdent) + " while dispatching to " |
44 | + msg.target.getClass().getName() + " " |
45 | + msg.callback + " what=" + msg.what); |
这个函数会调用Handler的dispatchMessage()方法来处理消息,其实也就是msg.target对象的dispatchMessage()方法。此外我们可以看到,在Looper.loop()方法的末尾recycle了从MessageQueue中取出的已经dispatch的消息。从而,我们需要通过Handler向一个Looper线程的MessageQueue中发送消息时,我们只要obtain一个Message然后发送就好了,而不需要自己手动去recycle,这些事情将会由Looper来帮助我们完成。接着来看Handler. dispatchMessage()的实现:
02 | * Handle system messages here. |
04 | public void dispatchMessage(Message msg) { |
05 | if (msg.callback != null ) { |
08 | if (mCallback != null ) { |
09 | if (mCallback.handleMessage(msg)) { |
在Message的callback成员为非空时,会执行handleCallback(msg),否则的话会依据Handler的mCallback是否为空来确定是否要执行mCallback.handleMessage(msg),并执行Handler的handleMessage(msg)。Handler的handleMessage()方法通常需要override,来实现消息处理的主要逻辑。而mCallback则使得开发者可以比较容易的添加一种对Message做一些额外检测的机制,以提升消息处理的效率。
接着我们看一下,Handler.handleCallback(msg)的实现:
1 | private static void handleCallback(Message message) { |
2 | message.callback.run(); |
很简单的一个方法。可见post的消息的特殊之处,即,此类消息将完全绕过Handler中用于处理消息的 handleMessage() 方法,而只会执行消息的sender所实现的Runnable。
Sleep-Wakeup机制
还有一个问题,当MessageQueue中没有Messages时,那Looper线程会做什么呢?它会去不停的轮询消息队列中是否有消息吗?计算机科学发展到现在,闭上眼睛我们都能知道,Looper线程将一定不会去轮询的。也确实,android消息队列机制的实现,同样是会在消息队列为空时,让Looper线程去休眠,当消息队列中有了消息之后,再被唤醒。但这样的机制又是如何实现的呢?
Sleep-Wakeup机制所需设施的建立
我们从Sleep-Wakeup机制所需设施的建立开始看起。回忆前面我们看到的Looper的构造函数,它会创建出来一个MessageQueue对象,而Sleep-Wakeup机制所需设施正是在MessageQueue对象的创建过程中创建出来的。我们接着再来看MessageQueue的构造函数:
1 | MessageQueue( boolean quitAllowed) { |
2 | mQuitAllowed = quitAllowed; |
这个方法调用nativeInit()方法来创建出Sleep-Wakeup机制所需设施。我们来看nativeInit()的实现(在frameworks/base/core/jni/android_os_MessageQueue.cpp中):
01 | NativeMessageQueue::NativeMessageQueue() : mInCallback( false ), mExceptionObj(NULL) { |
02 | mLooper = Looper::getForThread(); |
03 | if (mLooper == NULL) { |
04 | mLooper = new Looper( false ); |
05 | Looper::setForThread(mLooper); |
09 | static jint android_os_MessageQueue_nativeInit(JNIEnv* env, jclass clazz) { |
10 | NativeMessageQueue* nativeMessageQueue = new NativeMessageQueue(); |
11 | if (!nativeMessageQueue) { |
12 | jniThrowRuntimeException(env, "Unable to allocate native queue" ); |
16 | nativeMessageQueue->incStrong(env); |
17 | return reinterpret_cast <jint>(nativeMessageQueue); |
20 | static JNINativeMethod gMessageQueueMethods[] = { |
22 | { "nativeInit" , "()I" , ( void *)android_os_MessageQueue_nativeInit }, |
23 | { "nativeDestroy" , "(I)V" , ( void *)android_os_MessageQueue_nativeDestroy }, |
24 | { "nativePollOnce" , "(II)V" , ( void *)android_os_MessageQueue_nativePollOnce }, |
25 | { "nativeWake" , "(I)V" , ( void *)android_os_MessageQueue_nativeWake } |
可以看到,nativeInit()所做的事情,就是创建一个NativeMessageQueue对象,在NativeMessageQueue的构造函数中,会来创建一个Looper对象。与Java层的Looper对象类似,native层的这种Looper对象也是保存在线程局部存储变量中的,每个线程一个。接着我们来看Looper类的构造函数和Looper::getForThread()函数,来了解一下,native层的线程局部存储API的用法(Looper类的实现在frameworks/native/libs/utils/Looper.cpp):
02 | static const int EPOLL_SIZE_HINT = 8; |
05 | static const int EPOLL_MAX_EVENTS = 16; |
07 | static pthread_once_t gTLSOnce = PTHREAD_ONCE_INIT; |
08 | static pthread_key_t gTLSKey = 0; |
10 | Looper::Looper( bool allowNonCallbacks) : |
11 | mAllowNonCallbacks(allowNonCallbacks), mSendingMessage( false ), |
12 | mResponseIndex(0), mNextMessageUptime(LLONG_MAX) { |
14 | int result = pipe(wakeFds); |
15 | LOG_ALWAYS_FATAL_IF(result != 0, "Could not create wake pipe. errno=%d" , errno ); |
17 | mWakeReadPipeFd = wakeFds[0]; |
18 | mWakeWritePipeFd = wakeFds[1]; |
20 | result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK); |
21 | LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake read pipe non-blocking. errno=%d" , |
24 | result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK); |
25 | LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake write pipe non-blocking. errno=%d" , |
29 | mEpollFd = epoll_create(EPOLL_SIZE_HINT); |
30 | LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance. errno=%d" , errno ); |
32 | struct epoll_event eventItem; |
33 | memset (& eventItem, 0, sizeof (epoll_event)); |
34 | eventItem.events = EPOLLIN; |
35 | eventItem.data.fd = mWakeReadPipeFd; |
36 | result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, & eventItem); |
37 | LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake read pipe to epoll instance. errno=%d" , |
41 | void Looper::initTLSKey() { |
42 | int result = pthread_key_create(& gTLSKey, threadDestructor); |
43 | LOG_ALWAYS_FATAL_IF(result != 0, "Could not allocate TLS key." ); |
46 | void Looper::threadDestructor( void *st) { |
47 | Looper* const self = static_cast <Looper*>(st); |
49 | self->decStrong(( void *)threadDestructor); |
53 | void Looper::setForThread( const sp<Looper>& looper) { |
54 | sp<Looper> old = getForThread(); |
57 | looper->incStrong(( void *)threadDestructor); |
60 | pthread_setspecific(gTLSKey, looper.get()); |
63 | old->decStrong(( void *)threadDestructor); |
67 | sp<Looper> Looper::getForThread() { |
68 | int result = pthread_once(& gTLSOnce, initTLSKey); |
69 | LOG_ALWAYS_FATAL_IF(result != 0, "pthread_once failed" ); |
71 | return (Looper*)pthread_getspecific(gTLSKey); |
关于pthread库提供的线程局部存储API的用法,可以看到,每个线程局部存储对象,都需要一个key,通过pthread_key_create()函数创建,随后各个线程就可以通过这个key并借助于pthread_setspecific()和pthread_getspecific()函数来保存或者获取相应的线程局部存储的变量了。再来看Looper的构造函数。它创建了一个pipe,两个文件描述符。然后设置管道的两个文件描述属性为非阻塞I/O。接着是创建并设置epoll实例。由此我们了解到,android的消息队列是通过epoll机制来实现其Sleep-Wakeup机制的。
唤醒
然后来看当其他线程向Looper线程的MessageQueue中插入了消息时,Looper线程是如何被叫醒的。回忆我们前面看到的MessageQueue类的enqueueMessage()方法,它在最后插入消息之后,有调用一个nativeWake()方法。没错,正是这个nativeWake()方法执行了叫醒Looper线程的动作。那它又是如何叫醒Looper线程的呢?来看它的实现:
01 | static void android_os_MessageQueue_nativeWake(JNIEnv* env, jclass clazz, jint ptr) { |
02 | NativeMessageQueue* nativeMessageQueue = reinterpret_cast <NativeMessageQueue*>(ptr); |
03 | return nativeMessageQueue->wake(); |
08 | static JNINativeMethod gMessageQueueMethods[] = { |
10 | { "nativeInit" , "()I" , ( void *)android_os_MessageQueue_nativeInit }, |
11 | { "nativeDestroy" , "(I)V" , ( void *)android_os_MessageQueue_nativeDestroy }, |
12 | { "nativePollOnce" , "(II)V" , ( void *)android_os_MessageQueue_nativePollOnce }, |
13 | { "nativeWake" , "(I)V" , ( void *)android_os_MessageQueue_nativeWake } |
它只是调用了native层的Looper对象的wake()函数。接着再来看native Looper的wake()函数:
02 | #if DEBUG_POLL_AND_WAKE |
03 | ALOGD( "%p ~ wake" , this ); |
08 | nWrite = write(mWakeWritePipeFd, "W" , 1); |
09 | } while (nWrite == -1 && errno == EINTR); |
12 | if ( errno != EAGAIN) { |
13 | ALOGW( "Could not write wake signal, errno=%d" , errno ); |
它所做的事情,就是向管道的用于写的那个文件中写入一个“W”字符而已。
休眠
接着是Looper线程休眠的过程。我们知道,Looper线程在Looper.loop()方法中,将会不断地从MessageQueue中取出消息,并处理。不难想象,休眠的时机应该是在取出消息的时候。由Looper.loop()方法的code,我们知道,它是通过MessageQueue.next()方法来从消息队列中取出消息的。我们来看MessageQueue.next()方法的实现:
02 | int pendingIdleHandlerCount = - 1 ; |
03 | int nextPollTimeoutMillis = 0 ; |
06 | if (nextPollTimeoutMillis != 0 ) { |
07 | Binder.flushPendingCommands(); |
09 | nativePollOnce(mPtr, nextPollTimeoutMillis); |
13 | final long now = SystemClock.uptimeMillis(); |
14 | Message prevMsg = null ; |
15 | Message msg = mMessages; |
16 | if (msg != null && msg.target == null ) { |
21 | } while (msg != null && !msg.isAsynchronous()); |
26 | nextPollTimeoutMillis = ( int ) Math.min(msg.when - now, Integer.MAX_VALUE); |
30 | if (prevMsg != null ) { |
31 | prevMsg.next = msg.next; |
36 | if ( false ) Log.v( "MessageQueue" , "Returning message: " + msg); |
42 | nextPollTimeoutMillis = - 1 ; |
54 | if (pendingIdleHandlerCount < 0 |
55 | && (mMessages == null || now < mMessages.when)) { |
56 | pendingIdleHandlerCount = mIdleHandlers.size(); |
58 | if (pendingIdleHandlerCount <= 0 ) { |
64 | if (mPendingIdleHandlers == null ) { |
65 | mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4 )]; |
67 | mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers); |
72 | for ( int i = 0 ; i < pendingIdleHandlerCount; i++) { |
73 | final IdleHandler idler = mPendingIdleHandlers[i]; |
74 | mPendingIdleHandlers[i] = null ; |
78 | keep = idler.queueIdle(); |
79 | } catch (Throwable t) { |
80 | Log.wtf( "MessageQueue" , "IdleHandler threw exception" , t); |
85 | mIdleHandlers.remove(idler); |
91 | pendingIdleHandlerCount = 0 ; |
95 | nextPollTimeoutMillis = 0 ; |
值得注意的是上面那个对于nativePollOnce()的调用。wait机制的实现正在于此。来看这个方法的实现,在native的JNI code里面:
01 | class MessageQueue : public RefBase { |
04 | inline sp<Looper> getLooper() const { |
17 | bool raiseAndClearException(JNIEnv* env, const char * msg); |
31 | virtual void raiseException(JNIEnv* env, const char * msg, jthrowable exceptionObj) = 0; |
35 | virtual ~MessageQueue(); |
41 | class NativeMessageQueue : public MessageQueue { |
44 | virtual ~NativeMessageQueue(); |
46 | virtual void raiseException(JNIEnv* env, const char * msg, jthrowable exceptionObj); |
48 | void pollOnce(JNIEnv* env, int timeoutMillis); |
54 | jthrowable mExceptionObj; |
57 | void NativeMessageQueue::pollOnce(JNIEnv* env, int timeoutMillis) { |
59 | mLooper->pollOnce(timeoutMillis); |
62 | env->Throw(mExceptionObj); |
63 | env->DeleteLocalRef(mExceptionObj); |
68 | static void android_os_MessageQueue_nativePollOnce(JNIEnv* env, jclass clazz, |
69 | jint ptr, jint timeoutMillis) { |
70 | NativeMessageQueue* nativeMessageQueue = reinterpret_cast <NativeMessageQueue*>(ptr); |
71 | nativeMessageQueue->pollOnce(env, timeoutMillis); |
继续追Looper::pollOnce()的实现(在frameworks/native/libs/utils/Looper.cpp):
001 | int Looper::pollOnce( int timeoutMillis, int * outFd, int * outEvents, void ** outData) { |
004 | while (mResponseIndex < mResponses.size()) { |
005 | const Response& response = mResponses.itemAt(mResponseIndex++); |
006 | int ident = response.request.ident; |
008 | int fd = response.request.fd; |
009 | int events = response.events; |
010 | void * data = response.request.data; |
011 | #if DEBUG_POLL_AND_WAKE |
012 | ALOGD( "%p ~ pollOnce - returning signalled identifier %d: " |
013 | "fd=%d, events=0x%x, data=%p" , |
014 | this , ident, fd, events, data); |
016 | if (outFd != NULL) *outFd = fd; |
017 | if (outEvents != NULL) *outEvents = events; |
018 | if (outData != NULL) *outData = data; |
024 | #if DEBUG_POLL_AND_WAKE |
025 | ALOGD( "%p ~ pollOnce - returning result %d" , this , result); |
027 | if (outFd != NULL) *outFd = 0; |
028 | if (outEvents != NULL) *outEvents = 0; |
029 | if (outData != NULL) *outData = NULL; |
033 | result = pollInner(timeoutMillis); |
037 | int Looper::pollInner( int timeoutMillis) { |
038 | #if DEBUG_POLL_AND_WAKE |
039 | ALOGD( "%p ~ pollOnce - waiting: timeoutMillis=%d" , this , timeoutMillis); |
043 | if (timeoutMillis != 0 && mNextMessageUptime != LLONG_MAX) { |
044 | nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); |
045 | int messageTimeoutMillis = toMillisecondTimeoutDelay(now, mNextMessageUptime); |
046 | if (messageTimeoutMillis >= 0 |
047 | && (timeoutMillis < 0 || messageTimeoutMillis < timeoutMillis)) { |
048 | timeoutMillis = messageTimeoutMillis; |
050 | #if DEBUG_POLL_AND_WAKE |
051 | ALOGD( "%p ~ pollOnce - next message in %lldns, adjusted timeout: timeoutMillis=%d" , |
052 | this , mNextMessageUptime - now, timeoutMillis); |
057 | int result = ALOOPER_POLL_WAKE; |
061 | struct epoll_event eventItems[EPOLL_MAX_EVENTS]; |
062 | int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis); |
068 | if (eventCount < 0) { |
069 | if ( errno == EINTR) { |
072 | ALOGW( "Poll failed with an unexpected error, errno=%d" , errno ); |
073 | result = ALOOPER_POLL_ERROR; |
078 | if (eventCount == 0) { |
079 | #if DEBUG_POLL_AND_WAKE |
080 | ALOGD( "%p ~ pollOnce - timeout" , this ); |
082 | result = ALOOPER_POLL_TIMEOUT; |
087 | #if DEBUG_POLL_AND_WAKE |
088 | ALOGD( "%p ~ pollOnce - handling events from %d fds" , this , eventCount); |
091 | for ( int i = 0; i < eventCount; i++) { |
092 | int fd = eventItems[i].data.fd; |
093 | uint32_t epollEvents = eventItems[i].events; |
094 | if (fd == mWakeReadPipeFd) { |
095 | if (epollEvents & EPOLLIN) { |
098 | ALOGW( "Ignoring unexpected epoll events 0x%x on wake read pipe." , epollEvents); |
101 | ssize_t requestIndex = mRequests.indexOfKey(fd); |
102 | if (requestIndex >= 0) { |
104 | if (epollEvents & EPOLLIN) events |= ALOOPER_EVENT_INPUT; |
105 | if (epollEvents & EPOLLOUT) events |= ALOOPER_EVENT_OUTPUT; |
106 | if (epollEvents & EPOLLERR) events |= ALOOPER_EVENT_ERROR; |
107 | if (epollEvents & EPOLLHUP) events |= ALOOPER_EVENT_HANGUP; |
108 | pushResponse(events, mRequests.valueAt(requestIndex)); |
110 | ALOGW( "Ignoring unexpected epoll events 0x%x on fd %d that is " |
111 | "no longer registered." , epollEvents, fd); |
118 | mNextMessageUptime = LLONG_MAX; |
119 | while (mMessageEnvelopes.size() != 0) { |
120 | nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); |
121 | const MessageEnvelope& messageEnvelope = mMessageEnvelopes.itemAt(0); |
122 | if (messageEnvelope.uptime <= now) { |
128 | sp<MessageHandler> handler = messageEnvelope.handler; |
129 | Message message = messageEnvelope.message; |
130 | mMessageEnvelopes.removeAt(0); |
131 | mSendingMessage = true ; |
134 | #if DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKS |
135 | ALOGD( "%p ~ pollOnce - sending message: handler=%p, what=%d" , |
136 | this , handler.get(), message.what); |
138 | handler->handleMessage(message); |
142 | mSendingMessage = false ; |
143 | result = ALOOPER_POLL_CALLBACK; |
146 | mNextMessageUptime = messageEnvelope.uptime; |
155 | for ( size_t i = 0; i < mResponses.size(); i++) { |
156 | Response& response = mResponses.editItemAt(i); |
157 | if (response.request.ident == ALOOPER_POLL_CALLBACK) { |
158 | int fd = response.request.fd; |
159 | int events = response.events; |
160 | void * data = response.request.data; |
161 | #if DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKS |
162 | ALOGD( "%p ~ pollOnce - invoking fd event callback %p: fd=%d, events=0x%x, data=%p" , |
163 | this , response.request.callback.get(), fd, events, data); |
165 | int callbackResult = response.request.callback->handleEvent(fd, events, data); |
166 | if (callbackResult == 0) { |
171 | response.request.callback.clear(); |
172 | result = ALOOPER_POLL_CALLBACK; |
它通过调用epoll_wait()函数来等待消息的到来。
Done。
转载自http://my.oschina.net/wolfcs/blog/160601