简述:
继续Android Handler揭秘(一),这里来继续分析MessageQueue。
相关代码:
- frameworks/base/core/java/android/os/MessageQueue.java
- frameworks/base/core/jni/android_os_MessageQueue.cpp
- frameworks/base/core/java/android/os/Message.java
正文:
先写个test代码,然后根据test代码来分析代码。
01 public void test3() {
02 Log.d(TAG, "test3 start-->");
03 HandlerThread handlerThread = new HandlerThread("Test3");
04 handlerThread.start();
05 Handler handler = new Handler(handlerThread.getLooper()) {
06 @Override
07 public void handleMessage(Message msg) {
08 Log.d(TAG, "test3 handleMessage msg=" + msg + " Time=" + SystemClock.uptimeMillis());
09 }
10 };
11 Message msg = handler.obtainMessage(0, 0, 0, "msg");
12 handler.sendMessageDelayed(msg, 3000);
13 Log.d(TAG, "test3 send Msg0=" + msg + " Time=" + SystemClock.uptimeMillis());
14 msg = handler.obtainMessage(1, 0, 0, "msg1");
15 handler.sendMessageDelayed(msg, 6000);
16 Log.d(TAG, "test3 send Msg1=" + msg + " Time=" + SystemClock.uptimeMillis());
17 Log.d(TAG, "test3 end<--");
18 }
log输出:
2019-01-07 15:18:08.861 5819-5819/com.fy.platfromdebug D/TestHandler: test3 start-->
2019-01-07 15:18:08.865 5819-5819/com.fy.platfromdebug D/TestHandler: test3 send Msg0={ when=+3s0ms what=0 obj=msg target=com.fy.platfromdebug.TestHandler$1 } Time=177966090
2019-01-07 15:18:08.866 5819-5819/com.fy.platfromdebug D/TestHandler: test3 send Msg1={ when=+6s0ms what=1 obj=msg1 target=com.fy.platfromdebug.TestHandler$1 } Time=177966090
2019-01-07 15:18:08.867 5819-5819/com.fy.platfromdebug D/TestHandler: test3 end<--
2019-01-07 15:18:11.866 5819-5851/com.fy.platfromdebug D/TestHandler: test3 handleMessage msg={ when=-1ms what=0 obj=msg target=com.fy.platfromdebug.TestHandler$1 } Time=177969091
2019-01-07 15:18:14.869 5819-5851/com.fy.platfromdebug D/TestHandler: test3 handleMessage msg={ when=-4ms what=1 obj=msg1 target=com.fy.platfromdebug.TestHandler$1 } Time=177972094
从第11行开始分析,msg并不是写成直接Message msg = new Message(),原因是Message里面有做对象回收池(pool of recycled objects),有利于节省内存。handler.obtainMessage最终会调用到:
frameworks/base/core/java/android/os/Message.java
242 /**
243 * Same as {@link #obtain()}, but sets the values of the <em>target</em>, <em>what</em>,
244 * <em>arg1</em>, <em>arg2</em>, and <em>obj</em> members.
245 *
246 * @param h The <em>target</em> value to set.
247 * @param what The <em>what</em> value to set.
248 * @param arg1 The <em>arg1</em> value to set.
249 * @param arg2 The <em>arg2</em> value to set.
250 * @param obj The <em>obj</em> value to set.
251 * @return A Message object from the global pool.
252 */
253 public static Message obtain(Handler h, int what,
254 int arg1, int arg2, Object obj) {
255 Message m = obtain();
256 m.target = h;
257 m.what = what;
258 m.arg1 = arg1;
259 m.arg2 = arg2;
260 m.obj = obj;
261
262 return m;
263 }
缓存的关键就在于255 行Message m = obtain();
frameworks/base/core/java/android/os/Message.java
122 /**
123 * Return a new Message instance from the global pool. Allows us to
124 * avoid allocating new objects in many cases.
125 */
126 public static Message obtain() {
127 synchronized (sPoolSync) {
128 if (sPool != null) {
129 Message m = sPool;
130 sPool = m.next;
131 m.next = null;
132 m.flags = 0; // clear in-use flag
133 sPoolSize--;
134 return m;
135 }
136 }
137 return new Message();
138 }
加上下面的方法,就可以知道缓存的工作原理了。
frameworks/base/core/java/android/os/Message.java
291 /**
292 * Recycles a Message that may be in-use.
293 * Used internally by the MessageQueue and Looper when disposing of queued Messages.
294 */
295 void recycleUnchecked() {
296 // Mark the message as in use while it remains in the recycled object pool.
297 // Clear out all other details.
298 flags = FLAG_IN_USE;
299 what = 0;
300 arg1 = 0;
301 arg2 = 0;
302 obj = null;
303 replyTo = null;
304 sendingUid = -1;
305 when = 0;
306 target = null;
307 callback = null;
308 data = null;
309
310 synchronized (sPoolSync) {
311 if (sPoolSize < MAX_POOL_SIZE) {
312 next = sPool;
313 sPool = this;
314 sPoolSize++;
315 }
316 }
317 }
当有Message不再有用的时候,清空成员的值,然后判断下,当前对象回收池里面存的个数,如果小于MAX_POOL_SIZE,就将这个Message插入sPool链表,这样这个对象会被引用起来,系统不会回收,同时sPoolSize加1。
当我们需要新建一个Message时,通过public static Message obtain()方法,从sPool链表里面取出一个Message(如果sPool链表里面没有时才new一个Message),同时对sPoolSize减1。
这里的链表操作都是有加锁同步,确保多线程操作不会有问题。
分析完Message链表缓存机制。回到test3代码第12行handler.sendMessageDelayed(msg, 3000),此函数最终调用至
frameworks/base/core/java/android/os/MessageQueue.java
536 boolean enqueueMessage(Message msg, long when) {
//异常判断
537 if (msg.target == null) {
538 throw new IllegalArgumentException("Message must have a target.");
539 }
540 if (msg.isInUse()) {
541 throw new IllegalStateException(msg + " This message is already in use.");
542 }
543
//加锁同步
544 synchronized (this) {
545 if (mQuitting) {
546 IllegalStateException e = new IllegalStateException(
547 msg.target + " sending message to a Handler on a dead thread");
548 Log.w(TAG, e.getMessage(), e);
549 msg.recycle();
550 return false;
551 }
552
553 msg.markInUse();//标记使用
554 msg.when = when;
555 Message p = mMessages;
556 boolean needWake;
557 if (p == null || when == 0 || when < p.when) {//链表为空或者时间小于链表第一个消息,将消息插入链表第一个
558 // New head, wake up the event queue if blocked.
559 msg.next = p;
560 mMessages = msg;
561 needWake = mBlocked;
562 } else {//将消息按when来插入合适的位置
563 // Inserted within the middle of the queue. Usually we don't have to wake
564 // up the event queue unless there is a barrier at the head of the queue
565 // and the message is the earliest asynchronous message in the queue.
566 needWake = mBlocked && p.target == null && msg.isAsynchronous();
567 Message prev;
568 for (;;) {
569 prev = p;
570 p = p.next;
571 if (p == null || when < p.when) {
572 break;
573 }
574 if (needWake && p.isAsynchronous()) {
575 needWake = false;
576 }
577 }
578 msg.next = p; // invariant: p == prev.next
579 prev.next = msg;
580 }
581
582 // We can assume mPtr != 0 because mQuitting is false.
583 if (needWake) {//mBlocked在next方法里面设值,其实就是当前线程处理等待的时候,才需要唤醒
584 nativeWake(mPtr);
585 }
586 }
587 return true;
588 }
逻辑很简单,如果当前MessageQueue的mMessages是否有过链表,如果没有,就把链表设置为参数msg。如果有,就根据msg的触发时间when插入mMessages链表。这里有个needWake,根据mBlocked等条件来判断是否需要调用nativeWake。到这里,我们看到了native调用。其实MessageQueue实例化的时候就调用了nativeInit,且后再提。先来看看这里的mBlocked变量被改的方法next()(next方法是被Looper.loop()方法循环里面调用的)。
Tips:
- next方法是被Looper.loop()方法循环里面调用的。
- Message有个成员变量 Message next,然后再加上MessageQueue的mMessages prev,就是一个链表了。
frameworks/base/core/java/android/os/MessageQueue.java
310 Message next() {
311 // Return here if the message loop has already quit and been disposed.
312 // This can happen if the application tries to restart a looper after quit
313 // which is not supported.
314 final long ptr = mPtr;//mPtr是持有的native层的NativeMessageQueue对象
315 if (ptr == 0) {
316 return null;
317 }
318
319 int pendingIdleHandlerCount = -1; // -1 only during first iteration
320 int nextPollTimeoutMillis = 0;
321 for (;;) {
322 if (nextPollTimeoutMillis != 0) {
323 Binder.flushPendingCommands();
324 }
325
//实际上是调用Looper.cpp里面的pollOnce,基于linux的epoll,后续详细分析
326 nativePollOnce(ptr, nextPollTimeoutMillis);
327
328 synchronized (this) {
329 // Try to retrieve the next message. Return if found.
330 final long now = SystemClock.uptimeMillis();
331 Message prevMsg = null;
332 Message msg = mMessages;
333 if (msg != null && msg.target == null) {//当前是屏障状态,跟android的vsync刷新机制有关系
334 // Stalled by a barrier. Find the next asynchronous message in the queue.
335 do {//过滤掉不是异步处理的msg
336 prevMsg = msg;
337 msg = msg.next;
338 } while (msg != null && !msg.isAsynchronous());
339 }
340 if (msg != null) {
341 if (now < msg.when) {//当前消息时间嗨没到,设置nextPollTimeoutMillis,然后通知native去pollOnce等待
342 // Next message is not ready. Set a timeout to wake up when it is ready.
343 nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
344 } else {//时间已经到,返回消息给Looper进行分发处理
345 // Got a message.
346 mBlocked = false;
347 if (prevMsg != null) {
348 prevMsg.next = msg.next;
349 } else {
350 mMessages = msg.next;
351 }
352 msg.next = null;
353 if (DEBUG) Log.v(TAG, "Returning message: " + msg);
354 msg.markInUse();
355 return msg;
356 }
357 } else {
358 // No more messages.
359 nextPollTimeoutMillis = -1;
360 }
361
362 // Process the quit message now that all pending messages have been handled.
363 if (mQuitting) {
364 dispose();
365 return null;
366 }
367
//下面的用于mIdleHandlers状态的一些处理,比如GC
368 // If first time idle, then get the number of idlers to run.
369 // Idle handles only run if the queue is empty or if the first message
370 // in the queue (possibly a barrier) is due to be handled in the future.
371 if (pendingIdleHandlerCount < 0
372 && (mMessages == null || now < mMessages.when)) {
373 pendingIdleHandlerCount = mIdleHandlers.size();
374 }
375 if (pendingIdleHandlerCount <= 0) {
376 // No idle handlers to run. Loop and wait some more.
377 mBlocked = true;//标记下次enqueueMessage的时候,需要唤醒
378 continue;
379 }
380
381 if (mPendingIdleHandlers == null) {
382 mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
383 }
384 mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
385 }
386
387 // Run the idle handlers.
388 // We only ever reach this code block during the first iteration.
389 for (int i = 0; i < pendingIdleHandlerCount; i++) {
390 final IdleHandler idler = mPendingIdleHandlers[i];
391 mPendingIdleHandlers[i] = null; // release the reference to the handler
392
393 boolean keep = false;
394 try {
395 keep = idler.queueIdle();
396 } catch (Throwable t) {
397 Log.wtf(TAG, "IdleHandler threw exception", t);
398 }
399
400 if (!keep) {
401 synchronized (this) {
402 mIdleHandlers.remove(idler);
403 }
404 }
405 }
406
407 // Reset the idle handler count to 0 so we do not run them again.
408 pendingIdleHandlerCount = 0;
409
410 // While calling an idle handler, a new message could have been delivered
411 // so go back and look again for a pending message without waiting.
412 nextPollTimeoutMillis = 0;
413 }
414 }
最后来看下Looper调用MessageQueue的next方法的地方,Looper.loop(),去掉了一些计算分发时间代码。
frameworks/base/core/java/android/os/Looper.java
/**
134 * Run the message queue in this thread. Be sure to call
135 * {@link #quit()} to end the loop.
136 */
137 public static void loop() {
138 final Looper me = myLooper();
139 if (me == null) {
140 throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
141 }
142 final MessageQueue queue = me.mQueue;//取出链表
143
144 // Make sure the identity of this thread is that of the local process,
145 // and keep track of what that identity token actually is.
146 Binder.clearCallingIdentity();
147 final long ident = Binder.clearCallingIdentity();
148
...
158
159 for (;;) {
//这里取出消息,如果消息时间未到,会被block
160 Message msg = queue.next(); // might block
161 if (msg == null) {
162 // No message indicates that the message queue is quitting.
163 return;
164 }
165
...
//分发处理消息,调用msg的handler处理消息,最终回调callback/override的handleMessage(msg),对应到test代码就是07行的handleMessage
192 try {
193 msg.target.dispatchMessage(msg);
194 dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
195 } finally {
196 if (traceTag != 0) {
197 Trace.traceEnd(traceTag);
198 }
199 }
...
222 // Make sure that during the course of dispatching the
223 // identity of the thread wasn't corrupted.
224 final long newIdent = Binder.clearCallingIdentity();
225 if (ident != newIdent) {
226 Log.wtf(TAG, "Thread identity changed from 0x"
227 + Long.toHexString(ident) + " to 0x"
228 + Long.toHexString(newIdent) + " while dispatching to "
229 + msg.target.getClass().getName() + " "
230 + msg.callback + " what=" + msg.what);
231 }
232
233 msg.recycleUnchecked();//消息recycle,是否真正的GC回收了,前面有讲述
234 }
235 }
到这里,消息分发处理的逻辑都走完。
但是中间有略去native层的业务,线程阻塞、线程唤醒、native层的MessageQueue等,请见下回讲解。