xref: /aosp_15_r20/frameworks/base/core/java/android/os/CombinedMessageQueue/MessageQueue.java (revision d57664e9bc4670b3ecf6748a746a57c557b6bc9e)
1 /*
2  * Copyright (C) 2006 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.os;
18 
19 import android.annotation.IntDef;
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.annotation.SuppressLint;
23 import android.annotation.TestApi;
24 import android.app.ActivityThread;
25 import android.app.Instrumentation;
26 import android.compat.annotation.UnsupportedAppUsage;
27 import android.os.Process;
28 import android.os.UserHandle;
29 import android.ravenwood.annotation.RavenwoodKeepWholeClass;
30 import android.ravenwood.annotation.RavenwoodRedirect;
31 import android.ravenwood.annotation.RavenwoodRedirectionClass;
32 import android.ravenwood.annotation.RavenwoodReplace;
33 import android.ravenwood.annotation.RavenwoodThrow;
34 import android.util.Log;
35 import android.util.Printer;
36 import android.util.SparseArray;
37 import android.util.proto.ProtoOutputStream;
38 
39 import com.android.internal.annotations.GuardedBy;
40 import com.android.internal.ravenwood.RavenwoodEnvironment;
41 
42 import dalvik.annotation.optimization.NeverCompile;
43 
44 import java.io.FileDescriptor;
45 import java.lang.annotation.Retention;
46 import java.lang.annotation.RetentionPolicy;
47 import java.lang.invoke.MethodHandles;
48 import java.lang.invoke.VarHandle;
49 import java.util.ArrayList;
50 import java.util.Iterator;
51 import java.util.NoSuchElementException;
52 import java.util.concurrent.ConcurrentSkipListSet;
53 import java.util.concurrent.atomic.AtomicInteger;
54 import java.util.concurrent.atomic.AtomicLong;
55 import java.util.concurrent.locks.Condition;
56 import java.util.concurrent.locks.ReentrantLock;
57 
58 /**
59  * Low-level class holding the list of messages to be dispatched by a
60  * {@link Looper}.  Messages are not added directly to a MessageQueue,
61  * but rather through {@link Handler} objects associated with the Looper.
62  *
63  * <p>You can retrieve the MessageQueue for the current thread with
64  * {@link Looper#myQueue() Looper.myQueue()}.
65  */
66 @RavenwoodKeepWholeClass
67 @RavenwoodRedirectionClass("MessageQueue_ravenwood")
68 public final class MessageQueue {
69     private static final String TAG_L = "LegacyMessageQueue";
70     private static final String TAG_C = "ConcurrentMessageQueue";
71     private static final boolean DEBUG = false;
72     private static final boolean TRACE = false;
73 
74     // True if the message queue can be quit.
75     @UnsupportedAppUsage
76     private final boolean mQuitAllowed;
77 
78     @UnsupportedAppUsage
79     @SuppressWarnings("unused")
80     private long mPtr; // used by native code
81 
82     @UnsupportedAppUsage
83     Message mMessages;
84     private Message mLast;
85     @UnsupportedAppUsage
86     private final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<IdleHandler>();
87     private SparseArray<FileDescriptorRecord> mFileDescriptorRecords;
88     private IdleHandler[] mPendingIdleHandlers;
89     private boolean mQuitting;
90 
91     // Indicates whether next() is blocked waiting in pollOnce() with a non-zero timeout.
92     private boolean mBlocked;
93 
94     // Tracks the number of async message. We use this in enqueueMessage() to avoid searching the
95     // queue for async messages when inserting a message at the tail.
96     private int mAsyncMessageCount;
97 
98     /**
99      * Select between two implementations of message queue. The legacy implementation is used
100      * by default as it provides maximum compatibility with applications and tests that
101      * reach into MessageQueue via the mMessages field. The concurrent implemmentation is used for
102      * system processes and provides a higher level of concurrency and higher enqueue throughput
103      * than the legacy implementation.
104      */
105     private final boolean mUseConcurrent;
106 
107     /**
108      * Caches process-level checks that determine `mUseConcurrent`.
109      * This is to avoid redoing checks that shouldn't change during the process's lifetime.
110      */
111     private static Boolean sIsProcessAllowedToUseConcurrent = null;
112 
113     @RavenwoodRedirect
nativeInit()114     private native static long nativeInit();
115     @RavenwoodRedirect
nativeDestroy(long ptr)116     private native static void nativeDestroy(long ptr);
117     @UnsupportedAppUsage
118     @RavenwoodRedirect
nativePollOnce(long ptr, int timeoutMillis)119     private native void nativePollOnce(long ptr, int timeoutMillis); /*non-static for callbacks*/
120     @RavenwoodRedirect
nativeWake(long ptr)121     private native static void nativeWake(long ptr);
122     @RavenwoodRedirect
nativeIsPolling(long ptr)123     private native static boolean nativeIsPolling(long ptr);
124     @RavenwoodRedirect
nativeSetFileDescriptorEvents(long ptr, int fd, int events)125     private native static void nativeSetFileDescriptorEvents(long ptr, int fd, int events);
126 
MessageQueue(boolean quitAllowed)127     MessageQueue(boolean quitAllowed) {
128         initIsProcessAllowedToUseConcurrent();
129         mUseConcurrent = sIsProcessAllowedToUseConcurrent && !isInstrumenting();
130         mQuitAllowed = quitAllowed;
131         mPtr = nativeInit();
132     }
133 
initIsProcessAllowedToUseConcurrent()134     private static void initIsProcessAllowedToUseConcurrent() {
135         if (sIsProcessAllowedToUseConcurrent != null) {
136             return;
137         }
138 
139         if (RavenwoodEnvironment.getInstance().isRunningOnRavenwood()) {
140             sIsProcessAllowedToUseConcurrent = false;
141             return;
142         }
143 
144         final String processName = Process.myProcessName();
145         if (processName == null) {
146             // Assume that this is a host-side test and avoid concurrent mode for now.
147             sIsProcessAllowedToUseConcurrent = false;
148             return;
149         }
150 
151         // Concurrent mode modifies behavior that is observable via reflection and is commonly
152         // used by tests.
153         // For now, we limit it to system processes to avoid breaking apps and their tests.
154         sIsProcessAllowedToUseConcurrent = UserHandle.isCore(Process.myUid());
155 
156         if (sIsProcessAllowedToUseConcurrent) {
157             // Some platform tests run in core UIDs.
158             // Use this awful heuristic to detect them.
159             if (processName.contains("test") || processName.contains("Test")) {
160                 sIsProcessAllowedToUseConcurrent = false;
161             }
162         } else {
163             // Also explicitly allow SystemUI processes.
164             // SystemUI doesn't run in a core UID, but we want to give it the performance boost,
165             // and we know that it's safe to use the concurrent implementation in SystemUI.
166             sIsProcessAllowedToUseConcurrent =
167                     processName.equals("com.android.systemui")
168                             || processName.startsWith("com.android.systemui:");
169             // On Android distributions where SystemUI has a different process name,
170             // the above condition may need to be adjusted accordingly.
171         }
172 
173         // We can lift these restrictions in the future after we've made it possible for test
174         // authors to test Looper and MessageQueue without resorting to reflection.
175 
176         // Holdback study.
177         if (sIsProcessAllowedToUseConcurrent && Flags.messageQueueForceLegacy()) {
178             sIsProcessAllowedToUseConcurrent = false;
179         }
180     }
181 
182     @RavenwoodReplace
throwIfNotTest()183     private static void throwIfNotTest() {
184         final ActivityThread activityThread = ActivityThread.currentActivityThread();
185         if (activityThread == null) {
186             // Only tests can reach here.
187             return;
188         }
189         final Instrumentation instrumentation = activityThread.getInstrumentation();
190         if (instrumentation == null) {
191             // Only tests can reach here.
192             return;
193         }
194         if (instrumentation.isInstrumenting()) {
195             return;
196         }
197         throw new IllegalStateException("Test-only API called not from a test!");
198     }
199 
throwIfNotTest$ravenwood()200     private static void throwIfNotTest$ravenwood() {
201         return;
202     }
203 
isInstrumenting()204     private static boolean isInstrumenting() {
205         final ActivityThread activityThread = ActivityThread.currentActivityThread();
206         if (activityThread == null) {
207             return false;
208         }
209         final Instrumentation instrumentation = activityThread.getInstrumentation();
210         return instrumentation != null && instrumentation.isInstrumenting();
211     }
212 
213     @Override
finalize()214     protected void finalize() throws Throwable {
215         try {
216             dispose();
217         } finally {
218             super.finalize();
219         }
220     }
221 
222     // Disposes of the underlying message queue.
223     // Must only be called on the looper thread or the finalizer.
dispose()224     private void dispose() {
225         if (mPtr != 0) {
226             nativeDestroy(mPtr);
227             mPtr = 0;
228         }
229     }
230 
231     private static final class MatchDeliverableMessages extends MessageCompare {
232         @Override
compareMessage(MessageNode n, Handler h, int what, Object object, Runnable r, long when)233         public boolean compareMessage(MessageNode n, Handler h, int what, Object object, Runnable r,
234                 long when) {
235             return n.mMessage.when <= when;
236         }
237     }
238     private final MatchDeliverableMessages mMatchDeliverableMessages =
239             new MatchDeliverableMessages();
240     /**
241      * Returns true if the looper has no pending messages which are due to be processed.
242      *
243      * <p>This method is safe to call from any thread.
244      *
245      * @return True if the looper is idle.
246      */
isIdle()247     public boolean isIdle() {
248         if (mUseConcurrent) {
249             final long now = SystemClock.uptimeMillis();
250 
251             if (stackHasMessages(null, 0, null, null, now, mMatchDeliverableMessages, false)) {
252                 return false;
253             }
254 
255             MessageNode msgNode = null;
256             MessageNode asyncMsgNode = null;
257 
258             if (!mPriorityQueue.isEmpty()) {
259                 try {
260                     msgNode = mPriorityQueue.first();
261                 } catch (NoSuchElementException e) { }
262             }
263 
264             if (!mAsyncPriorityQueue.isEmpty()) {
265                 try {
266                     asyncMsgNode = mAsyncPriorityQueue.first();
267                 } catch (NoSuchElementException e) { }
268             }
269 
270             if ((msgNode != null && msgNode.getWhen() <= now)
271                     || (asyncMsgNode != null && asyncMsgNode.getWhen() <= now)) {
272                 return false;
273             }
274 
275             return true;
276         } else {
277             synchronized (this) {
278                 final long now = SystemClock.uptimeMillis();
279                 return mMessages == null || now < mMessages.when;
280             }
281         }
282     }
283 
284     /**
285      * Add a new {@link IdleHandler} to this message queue.  This may be
286      * removed automatically for you by returning false from
287      * {@link IdleHandler#queueIdle IdleHandler.queueIdle()} when it is
288      * invoked, or explicitly removing it with {@link #removeIdleHandler}.
289      *
290      * <p>This method is safe to call from any thread.
291      *
292      * @param handler The IdleHandler to be added.
293      */
addIdleHandler(@onNull IdleHandler handler)294     public void addIdleHandler(@NonNull IdleHandler handler) {
295         if (handler == null) {
296             throw new NullPointerException("Can't add a null IdleHandler");
297         }
298         if (mUseConcurrent) {
299             synchronized (mIdleHandlersLock) {
300                 mIdleHandlers.add(handler);
301             }
302         } else {
303             synchronized (this) {
304                 mIdleHandlers.add(handler);
305             }
306         }
307     }
308 
309     /**
310      * Remove an {@link IdleHandler} from the queue that was previously added
311      * with {@link #addIdleHandler}.  If the given object is not currently
312      * in the idle list, nothing is done.
313      *
314      * <p>This method is safe to call from any thread.
315      *
316      * @param handler The IdleHandler to be removed.
317      */
removeIdleHandler(@onNull IdleHandler handler)318     public void removeIdleHandler(@NonNull IdleHandler handler) {
319         if (mUseConcurrent) {
320             synchronized (mIdleHandlersLock) {
321                 mIdleHandlers.remove(handler);
322             }
323         } else {
324             synchronized (this) {
325                 mIdleHandlers.remove(handler);
326             }
327         }
328     }
329 
330     /**
331      * Returns whether this looper's thread is currently polling for more work to do.
332      * This is a good signal that the loop is still alive rather than being stuck
333      * handling a callback.  Note that this method is intrinsically racy, since the
334      * state of the loop can change before you get the result back.
335      *
336      * <p>This method is safe to call from any thread.
337      *
338      * @return True if the looper is currently polling for events.
339      * @hide
340      */
isPolling()341     public boolean isPolling() {
342         if (mUseConcurrent) {
343             // If the loop is quitting then it must not be idling.
344             // We can assume mPtr != 0 when sQuitting is false.
345             return !((boolean) sQuitting.getVolatile(this)) && nativeIsPolling(mPtr);
346         } else {
347             synchronized (this) {
348                 return isPollingLocked();
349             }
350         }
351     }
352 
isPollingLocked()353     private boolean isPollingLocked() {
354         // If the loop is quitting then it must not be idling.
355         // We can assume mPtr != 0 when mQuitting is false.
356         return !mQuitting && nativeIsPolling(mPtr);
357     }
358 
359     /**
360      * Adds a file descriptor listener to receive notification when file descriptor
361      * related events occur.
362      * <p>
363      * If the file descriptor has already been registered, the specified events
364      * and listener will replace any that were previously associated with it.
365      * It is not possible to set more than one listener per file descriptor.
366      * </p><p>
367      * It is important to always unregister the listener when the file descriptor
368      * is no longer of use.
369      * </p>
370      *
371      * @param fd The file descriptor for which a listener will be registered.
372      * @param events The set of events to receive: a combination of the
373      * {@link OnFileDescriptorEventListener#EVENT_INPUT},
374      * {@link OnFileDescriptorEventListener#EVENT_OUTPUT}, and
375      * {@link OnFileDescriptorEventListener#EVENT_ERROR} event masks.  If the requested
376      * set of events is zero, then the listener is unregistered.
377      * @param listener The listener to invoke when file descriptor events occur.
378      *
379      * @see OnFileDescriptorEventListener
380      * @see #removeOnFileDescriptorEventListener
381      */
382     @RavenwoodThrow(blockedBy = android.os.ParcelFileDescriptor.class)
addOnFileDescriptorEventListener(@onNull FileDescriptor fd, @OnFileDescriptorEventListener.Events int events, @NonNull OnFileDescriptorEventListener listener)383     public void addOnFileDescriptorEventListener(@NonNull FileDescriptor fd,
384             @OnFileDescriptorEventListener.Events int events,
385             @NonNull OnFileDescriptorEventListener listener) {
386         if (fd == null) {
387             throw new IllegalArgumentException("fd must not be null");
388         }
389         if (listener == null) {
390             throw new IllegalArgumentException("listener must not be null");
391         }
392 
393         if (mUseConcurrent) {
394             synchronized (mFileDescriptorRecordsLock) {
395                 updateOnFileDescriptorEventListenerLocked(fd, events, listener);
396             }
397         } else {
398             synchronized (this) {
399                 updateOnFileDescriptorEventListenerLocked(fd, events, listener);
400             }
401         }
402     }
403 
404     /**
405      * Removes a file descriptor listener.
406      * <p>
407      * This method does nothing if no listener has been registered for the
408      * specified file descriptor.
409      * </p>
410      *
411      * @param fd The file descriptor whose listener will be unregistered.
412      *
413      * @see OnFileDescriptorEventListener
414      * @see #addOnFileDescriptorEventListener
415      */
416     @RavenwoodThrow(blockedBy = android.os.ParcelFileDescriptor.class)
removeOnFileDescriptorEventListener(@onNull FileDescriptor fd)417     public void removeOnFileDescriptorEventListener(@NonNull FileDescriptor fd) {
418         if (fd == null) {
419             throw new IllegalArgumentException("fd must not be null");
420         }
421         if (mUseConcurrent) {
422             synchronized (mFileDescriptorRecordsLock) {
423                 updateOnFileDescriptorEventListenerLocked(fd, 0, null);
424             }
425         } else {
426             synchronized (this) {
427                 updateOnFileDescriptorEventListenerLocked(fd, 0, null);
428             }
429         }
430     }
431 
432     @RavenwoodThrow(blockedBy = android.os.ParcelFileDescriptor.class)
updateOnFileDescriptorEventListenerLocked(FileDescriptor fd, int events, OnFileDescriptorEventListener listener)433     private void updateOnFileDescriptorEventListenerLocked(FileDescriptor fd, int events,
434             OnFileDescriptorEventListener listener) {
435         final int fdNum = fd.getInt$();
436 
437         int index = -1;
438         FileDescriptorRecord record = null;
439         if (mFileDescriptorRecords != null) {
440             index = mFileDescriptorRecords.indexOfKey(fdNum);
441             if (index >= 0) {
442                 record = mFileDescriptorRecords.valueAt(index);
443                 if (record != null && record.mEvents == events) {
444                     return;
445                 }
446             }
447         }
448 
449         if (events != 0) {
450             events |= OnFileDescriptorEventListener.EVENT_ERROR;
451             if (record == null) {
452                 if (mFileDescriptorRecords == null) {
453                     mFileDescriptorRecords = new SparseArray<FileDescriptorRecord>();
454                 }
455                 record = new FileDescriptorRecord(fd, events, listener);
456                 mFileDescriptorRecords.put(fdNum, record);
457             } else {
458                 record.mListener = listener;
459                 record.mEvents = events;
460                 record.mSeq += 1;
461             }
462             nativeSetFileDescriptorEvents(mPtr, fdNum, events);
463         } else if (record != null) {
464             record.mEvents = 0;
465             mFileDescriptorRecords.removeAt(index);
466             nativeSetFileDescriptorEvents(mPtr, fdNum, 0);
467         }
468     }
469 
470     // Called from native code.
471     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
dispatchEvents(int fd, int events)472     private int dispatchEvents(int fd, int events) {
473         // Get the file descriptor record and any state that might change.
474         final FileDescriptorRecord record;
475         final int oldWatchedEvents;
476         final OnFileDescriptorEventListener listener;
477         final int seq;
478         if (mUseConcurrent) {
479             synchronized (mFileDescriptorRecordsLock) {
480                 record = mFileDescriptorRecords.get(fd);
481                 if (record == null) {
482                     return 0; // spurious, no listener registered
483                 }
484 
485                 oldWatchedEvents = record.mEvents;
486                 events &= oldWatchedEvents; // filter events based on current watched set
487                 if (events == 0) {
488                     return oldWatchedEvents; // spurious, watched events changed
489                 }
490 
491                 listener = record.mListener;
492                 seq = record.mSeq;
493             }
494         } else {
495             synchronized (this) {
496                 record = mFileDescriptorRecords.get(fd);
497                 if (record == null) {
498                     return 0; // spurious, no listener registered
499                 }
500 
501                 oldWatchedEvents = record.mEvents;
502                 events &= oldWatchedEvents; // filter events based on current watched set
503                 if (events == 0) {
504                     return oldWatchedEvents; // spurious, watched events changed
505                 }
506 
507                 listener = record.mListener;
508                 seq = record.mSeq;
509             }
510         }
511         // Invoke the listener outside of the lock.
512         int newWatchedEvents = listener.onFileDescriptorEvents(
513                 record.mDescriptor, events);
514         if (newWatchedEvents != 0) {
515             newWatchedEvents |= OnFileDescriptorEventListener.EVENT_ERROR;
516         }
517 
518         // Update the file descriptor record if the listener changed the set of
519         // events to watch and the listener itself hasn't been updated since.
520         if (newWatchedEvents != oldWatchedEvents) {
521             if (mUseConcurrent) {
522                 synchronized (mFileDescriptorRecordsLock) {
523                     int index = mFileDescriptorRecords.indexOfKey(fd);
524                     if (index >= 0 && mFileDescriptorRecords.valueAt(index) == record
525                             && record.mSeq == seq) {
526                         record.mEvents = newWatchedEvents;
527                         if (newWatchedEvents == 0) {
528                             mFileDescriptorRecords.removeAt(index);
529                         }
530                     }
531                 }
532             } else {
533                 synchronized (this) {
534                     int index = mFileDescriptorRecords.indexOfKey(fd);
535                     if (index >= 0 && mFileDescriptorRecords.valueAt(index) == record
536                             && record.mSeq == seq) {
537                         record.mEvents = newWatchedEvents;
538                         if (newWatchedEvents == 0) {
539                             mFileDescriptorRecords.removeAt(index);
540                         }
541                     }
542                 }
543             }
544         }
545 
546         // Return the new set of events to watch for native code to take care of.
547         return newWatchedEvents;
548     }
549 
550     private static final AtomicLong mMessagesDelivered = new AtomicLong();
551 
552     /* This is only read/written from the Looper thread. For use with Concurrent MQ */
553     private int mNextPollTimeoutMillis;
554     private boolean mMessageDirectlyQueued;
nextMessage(boolean peek)555     private Message nextMessage(boolean peek) {
556         int i = 0;
557 
558         while (true) {
559             if (DEBUG) {
560                 Log.d(TAG_C, "nextMessage loop #" + i);
561                 i++;
562             }
563 
564             mDrainingLock.lock();
565             mNextIsDrainingStack = true;
566             mDrainingLock.unlock();
567 
568             /*
569              * Set our state to active, drain any items from the stack into our priority queues
570              */
571             StackNode oldTop;
572             oldTop = swapAndSetStackStateActive();
573             drainStack(oldTop);
574 
575             mDrainingLock.lock();
576             mNextIsDrainingStack = false;
577             mDrainCompleted.signalAll();
578             mDrainingLock.unlock();
579 
580             /*
581              * The objective of this next block of code is to:
582              *  - find a message to return (if any is ready)
583              *  - find a next message we would like to return, after scheduling.
584              *     - we make our scheduling decision based on this next message (if it exists).
585              *
586              * We have two queues to juggle and the presence of barriers throws an additional
587              * wrench into our plans.
588              *
589              * The last wrinkle is that remove() may delete items from underneath us. If we hit
590              * that case, we simply restart the loop.
591              */
592 
593             /* Get the first node from each queue */
594             Iterator<MessageNode> queueIter = mPriorityQueue.iterator();
595             MessageNode msgNode = iterateNext(queueIter);
596             Iterator<MessageNode> asyncQueueIter = mAsyncPriorityQueue.iterator();
597             MessageNode asyncMsgNode = iterateNext(asyncQueueIter);
598 
599             if (DEBUG) {
600                 if (msgNode != null) {
601                     Message msg = msgNode.mMessage;
602                     Log.d(TAG_C, "Next found node what: " + msg.what + " when: " + msg.when
603                             + " seq: " + msgNode.mInsertSeq + "barrier: "
604                             + msgNode.isBarrier() + " now: " + SystemClock.uptimeMillis());
605                 }
606                 if (asyncMsgNode != null) {
607                     Message msg = asyncMsgNode.mMessage;
608                     Log.d(TAG_C, "Next found async node what: " + msg.what + " when: " + msg.when
609                             + " seq: " + asyncMsgNode.mInsertSeq + "barrier: "
610                             + asyncMsgNode.isBarrier() + " now: "
611                             + SystemClock.uptimeMillis());
612                 }
613             }
614 
615             /*
616              * the node which we will return, null if none are ready
617              */
618             MessageNode found = null;
619             /*
620              * The node from which we will determine our next wakeup time.
621              * Null indicates there is no next message ready. If we found a node,
622              * we can leave this null as Looper will call us again after delivering
623              * the message.
624              */
625             MessageNode next = null;
626 
627             long now = SystemClock.uptimeMillis();
628             /*
629              * If we have a barrier we should return the async node (if it exists and is ready)
630              */
631             if (msgNode != null && msgNode.isBarrier()) {
632                 if (asyncMsgNode != null && now >= asyncMsgNode.getWhen()) {
633                     found = asyncMsgNode;
634                 } else {
635                     next = asyncMsgNode;
636                 }
637             } else { /* No barrier. */
638                 MessageNode earliest;
639                 /*
640                  * If we have two messages, pick the earliest option from either queue.
641                  * Otherwise grab whichever node is non-null. If both are null we'll fall through.
642                  */
643                 earliest = pickEarliestNode(msgNode, asyncMsgNode);
644 
645                 if (earliest != null) {
646                     if (now >= earliest.getWhen()) {
647                         found = earliest;
648                     } else {
649                         next = earliest;
650                     }
651                 }
652             }
653 
654             if (DEBUG) {
655                 if (found != null) {
656                     Message msg = found.mMessage;
657                     Log.d(TAG_C, " Will deliver node what: " + msg.what + " when: " + msg.when
658                             + " seq: " + found.mInsertSeq + " barrier: " + found.isBarrier()
659                             + " async: " + found.isAsync() + " now: "
660                             + SystemClock.uptimeMillis());
661                 } else {
662                     Log.d(TAG_C, "No node to deliver");
663                 }
664                 if (next != null) {
665                     Message msg = next.mMessage;
666                     Log.d(TAG_C, "Next node what: " + msg.what + " when: " + msg.when + " seq: "
667                             + next.mInsertSeq + " barrier: " + next.isBarrier() + " async: "
668                             + next.isAsync()
669                             + " now: " + SystemClock.uptimeMillis());
670                 } else {
671                     Log.d(TAG_C, "No next node");
672                 }
673             }
674 
675             /*
676              * If we have a found message, we will get called again so there's no need to set state.
677              * In that case we can leave our state as ACTIVE.
678              *
679              * Otherwise we should determine how to park the thread.
680              */
681             StateNode nextOp = sStackStateActive;
682             if (found == null) {
683                 if (next == null) {
684                     /* No message to deliver, sleep indefinitely */
685                     mNextPollTimeoutMillis = -1;
686                     nextOp = sStackStateParked;
687                     if (DEBUG) {
688                         Log.d(TAG_C, "nextMessage next state is StackStateParked");
689                     }
690                 } else {
691                     /* Message not ready, or we found one to deliver already, set a timeout */
692                     long nextMessageWhen = next.getWhen();
693                     if (nextMessageWhen > now) {
694                         mNextPollTimeoutMillis = (int) Math.min(nextMessageWhen - now,
695                                 Integer.MAX_VALUE);
696                     } else {
697                         mNextPollTimeoutMillis = 0;
698                     }
699 
700                     mStackStateTimedPark.mWhenToWake = now + mNextPollTimeoutMillis;
701                     nextOp = mStackStateTimedPark;
702                     if (DEBUG) {
703                         Log.d(TAG_C, "nextMessage next state is StackStateTimedParked timeout ms "
704                                 + mNextPollTimeoutMillis + " mWhenToWake: "
705                                 + mStackStateTimedPark.mWhenToWake + " now " + now);
706                     }
707                 }
708             }
709 
710             /*
711              * Try to swap our state from Active back to Park or TimedPark. If we raced with
712              * enqueue, loop back around to pick up any new items.
713              */
714             if (sState.compareAndSet(this, sStackStateActive, nextOp)) {
715                 mMessageCounts.clearCounts();
716                 if (found != null) {
717                     if (!peek && !removeFromPriorityQueue(found)) {
718                         /*
719                          * RemoveMessages() might be able to pull messages out from under us
720                          * However we can detect that here and just loop around if it happens.
721                          */
722                         continue;
723                     }
724 
725                     if (TRACE) {
726                         Trace.setCounter("MQ.Delivered", mMessagesDelivered.incrementAndGet());
727                     }
728                     return found.mMessage;
729                 }
730                 return null;
731             }
732         }
733     }
734 
nextConcurrent()735     private Message nextConcurrent() {
736         final long ptr = mPtr;
737         if (ptr == 0) {
738             return null;
739         }
740 
741         mNextPollTimeoutMillis = 0;
742         int pendingIdleHandlerCount = -1; // -1 only during first iteration
743         while (true) {
744             if (mNextPollTimeoutMillis != 0) {
745                 Binder.flushPendingCommands();
746             }
747 
748             mMessageDirectlyQueued = false;
749             nativePollOnce(ptr, mNextPollTimeoutMillis);
750 
751             Message msg = nextMessage(false);
752             if (msg != null) {
753                 msg.markInUse();
754                 return msg;
755             }
756 
757             if ((boolean) sQuitting.getVolatile(this)) {
758                 return null;
759             }
760 
761             synchronized (mIdleHandlersLock) {
762                 // If first time idle, then get the number of idlers to run.
763                 // Idle handles only run if the queue is empty or if the first message
764                 // in the queue (possibly a barrier) is due to be handled in the future.
765                 if (pendingIdleHandlerCount < 0
766                         && isIdle()) {
767                     pendingIdleHandlerCount = mIdleHandlers.size();
768                 }
769                 if (pendingIdleHandlerCount <= 0) {
770                     // No idle handlers to run.  Loop and wait some more.
771                     continue;
772                 }
773 
774                 if (mPendingIdleHandlers == null) {
775                     mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
776                 }
777                 mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
778             }
779 
780             // Run the idle handlers.
781             // We only ever reach this code block during the first iteration.
782             for (int i = 0; i < pendingIdleHandlerCount; i++) {
783                 final IdleHandler idler = mPendingIdleHandlers[i];
784                 mPendingIdleHandlers[i] = null; // release the reference to the handler
785 
786                 boolean keep = false;
787                 try {
788                     keep = idler.queueIdle();
789                 } catch (Throwable t) {
790                     Log.wtf(TAG_C, "IdleHandler threw exception", t);
791                 }
792 
793                 if (!keep) {
794                     synchronized (mIdleHandlersLock) {
795                         mIdleHandlers.remove(idler);
796                     }
797                 }
798             }
799 
800             // Reset the idle handler count to 0 so we do not run them again.
801             pendingIdleHandlerCount = 0;
802 
803             // While calling an idle handler, a new message could have been delivered
804             // so go back and look again for a pending message without waiting.
805             mNextPollTimeoutMillis = 0;
806         }
807     }
808 
809     @UnsupportedAppUsage
next()810     Message next() {
811         if (mUseConcurrent) {
812             return nextConcurrent();
813         }
814 
815         // Return here if the message loop has already quit and been disposed.
816         // This can happen if the application tries to restart a looper after quit
817         // which is not supported.
818         final long ptr = mPtr;
819         if (ptr == 0) {
820             return null;
821         }
822 
823         int pendingIdleHandlerCount = -1; // -1 only during first iteration
824         int nextPollTimeoutMillis = 0;
825         for (;;) {
826             if (nextPollTimeoutMillis != 0) {
827                 Binder.flushPendingCommands();
828             }
829 
830             nativePollOnce(ptr, nextPollTimeoutMillis);
831 
832             synchronized (this) {
833                 // Try to retrieve the next message.  Return if found.
834                 final long now = SystemClock.uptimeMillis();
835                 Message prevMsg = null;
836                 Message msg = mMessages;
837                 if (msg != null && msg.target == null) {
838                     // Stalled by a barrier.  Find the next asynchronous message in the queue.
839                     do {
840                         prevMsg = msg;
841                         msg = msg.next;
842                     } while (msg != null && !msg.isAsynchronous());
843                 }
844                 if (msg != null) {
845                     if (now < msg.when) {
846                         // Next message is not ready.  Set a timeout to wake up when it is ready.
847                         nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
848                     } else {
849                         // Got a message.
850                         mBlocked = false;
851                         if (prevMsg != null) {
852                             prevMsg.next = msg.next;
853                             if (prevMsg.next == null) {
854                                 mLast = prevMsg;
855                             }
856                         } else {
857                             mMessages = msg.next;
858                             if (msg.next == null) {
859                                 mLast = null;
860                             }
861                         }
862                         msg.next = null;
863                         if (DEBUG) Log.v(TAG_L, "Returning message: " + msg);
864                         msg.markInUse();
865                         if (msg.isAsynchronous()) {
866                             mAsyncMessageCount--;
867                         }
868                         if (TRACE) {
869                             Trace.setCounter("MQ.Delivered", mMessagesDelivered.incrementAndGet());
870                         }
871                         return msg;
872                     }
873                 } else {
874                     // No more messages.
875                     nextPollTimeoutMillis = -1;
876                 }
877 
878                 // Process the quit message now that all pending messages have been handled.
879                 if (mQuitting) {
880                     dispose();
881                     return null;
882                 }
883 
884                 // If first time idle, then get the number of idlers to run.
885                 // Idle handles only run if the queue is empty or if the first message
886                 // in the queue (possibly a barrier) is due to be handled in the future.
887                 if (pendingIdleHandlerCount < 0
888                         && (mMessages == null || now < mMessages.when)) {
889                     pendingIdleHandlerCount = mIdleHandlers.size();
890                 }
891                 if (pendingIdleHandlerCount <= 0) {
892                     // No idle handlers to run.  Loop and wait some more.
893                     mBlocked = true;
894                     continue;
895                 }
896 
897                 if (mPendingIdleHandlers == null) {
898                     mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
899                 }
900                 mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
901             }
902 
903             // Run the idle handlers.
904             // We only ever reach this code block during the first iteration.
905             for (int i = 0; i < pendingIdleHandlerCount; i++) {
906                 final IdleHandler idler = mPendingIdleHandlers[i];
907                 mPendingIdleHandlers[i] = null; // release the reference to the handler
908 
909                 boolean keep = false;
910                 try {
911                     keep = idler.queueIdle();
912                 } catch (Throwable t) {
913                     Log.wtf(TAG_L, "IdleHandler threw exception", t);
914                 }
915 
916                 if (!keep) {
917                     synchronized (this) {
918                         mIdleHandlers.remove(idler);
919                     }
920                 }
921             }
922 
923             // Reset the idle handler count to 0 so we do not run them again.
924             pendingIdleHandlerCount = 0;
925 
926             // While calling an idle handler, a new message could have been delivered
927             // so go back and look again for a pending message without waiting.
928             nextPollTimeoutMillis = 0;
929         }
930     }
931 
quit(boolean safe)932     void quit(boolean safe) {
933         if (!mQuitAllowed) {
934             throw new IllegalStateException("Main thread not allowed to quit.");
935         }
936 
937         if (mUseConcurrent) {
938             synchronized (mIdleHandlersLock) {
939                 if (sQuitting.compareAndSet(this, false, true)) {
940                     if (safe) {
941                         removeAllFutureMessages();
942                     } else {
943                         removeAllMessages();
944                     }
945 
946                     // We can assume mPtr != 0 because sQuitting was previously false.
947                     nativeWake(mPtr);
948                 }
949             }
950         } else {
951             synchronized (this) {
952                 if (mQuitting) {
953                     return;
954                 }
955                 mQuitting = true;
956 
957                 if (safe) {
958                     removeAllFutureMessagesLocked();
959                 } else {
960                     removeAllMessagesLocked();
961                 }
962 
963                 // We can assume mPtr != 0 because mQuitting was previously false.
964                 nativeWake(mPtr);
965             }
966         }
967     }
968 
969     /**
970      * Posts a synchronization barrier to the Looper's message queue.
971      *
972      * Message processing occurs as usual until the message queue encounters the
973      * synchronization barrier that has been posted.  When the barrier is encountered,
974      * later synchronous messages in the queue are stalled (prevented from being executed)
975      * until the barrier is released by calling {@link #removeSyncBarrier} and specifying
976      * the token that identifies the synchronization barrier.
977      *
978      * This method is used to immediately postpone execution of all subsequently posted
979      * synchronous messages until a condition is met that releases the barrier.
980      * Asynchronous messages (see {@link Message#isAsynchronous} are exempt from the barrier
981      * and continue to be processed as usual.
982      *
983      * This call must be always matched by a call to {@link #removeSyncBarrier} with
984      * the same token to ensure that the message queue resumes normal operation.
985      * Otherwise the application will probably hang!
986      *
987      * @return A token that uniquely identifies the barrier.  This token must be
988      * passed to {@link #removeSyncBarrier} to release the barrier.
989      *
990      * @hide
991      */
992     @UnsupportedAppUsage
993     @TestApi
postSyncBarrier()994     public int postSyncBarrier() {
995         return postSyncBarrier(SystemClock.uptimeMillis());
996     }
997 
postSyncBarrier(long when)998     private int postSyncBarrier(long when) {
999         // Enqueue a new sync barrier token.
1000         // We don't need to wake the queue because the purpose of a barrier is to stall it.
1001         if (mUseConcurrent) {
1002             final int token = mNextBarrierTokenAtomic.getAndIncrement();
1003 
1004             // b/376573804: apps and tests may expect to be able to use reflection
1005             // to read this value. Make some effort to support this legacy use case.
1006             mNextBarrierToken = token + 1;
1007 
1008             final Message msg = Message.obtain();
1009 
1010             msg.markInUse();
1011             msg.arg1 = token;
1012 
1013             if (!enqueueMessageUnchecked(msg, when)) {
1014                 Log.wtf(TAG_C, "Unexpected error while adding sync barrier!");
1015                 return -1;
1016             }
1017 
1018             return token;
1019         }
1020 
1021         synchronized (this) {
1022             final int token = mNextBarrierToken++;
1023             final Message msg = Message.obtain();
1024             msg.markInUse();
1025             msg.when = when;
1026             msg.arg1 = token;
1027 
1028             if (Flags.messageQueueTailTracking() && mLast != null && mLast.when <= when) {
1029                 /* Message goes to tail of list */
1030                 mLast.next = msg;
1031                 mLast = msg;
1032                 msg.next = null;
1033                 return token;
1034             }
1035 
1036             Message prev = null;
1037             Message p = mMessages;
1038             if (when != 0) {
1039                 while (p != null && p.when <= when) {
1040                     prev = p;
1041                     p = p.next;
1042                 }
1043             }
1044 
1045             if (p == null) {
1046                 /* We reached the tail of the list, or list is empty. */
1047                 mLast = msg;
1048             }
1049 
1050             if (prev != null) { // invariant: p == prev.next
1051                 msg.next = p;
1052                 prev.next = msg;
1053             } else {
1054                 msg.next = p;
1055                 mMessages = msg;
1056             }
1057             return token;
1058         }
1059     }
1060 
1061     private static final class MatchBarrierToken extends MessageCompare {
1062         int mBarrierToken;
1063 
MatchBarrierToken(int token)1064         MatchBarrierToken(int token) {
1065             super();
1066             mBarrierToken = token;
1067         }
1068 
1069         @Override
compareMessage(MessageNode n, Handler h, int what, Object object, Runnable r, long when)1070         public boolean compareMessage(MessageNode n, Handler h, int what, Object object, Runnable r,
1071                 long when) {
1072             final Message m = n.mMessage;
1073             if (m.target == null && m.arg1 == mBarrierToken) {
1074                 return true;
1075             }
1076             return false;
1077         }
1078     }
1079 
1080     /**
1081      * Removes a synchronization barrier.
1082      *
1083      * @param token The synchronization barrier token that was returned by
1084      * {@link #postSyncBarrier}.
1085      *
1086      * @throws IllegalStateException if the barrier was not found.
1087      *
1088      * @hide
1089      */
1090     @UnsupportedAppUsage
1091     @TestApi
removeSyncBarrier(int token)1092     public void removeSyncBarrier(int token) {
1093         // Remove a sync barrier token from the queue.
1094         // If the queue is no longer stalled by a barrier then wake it.
1095         if (mUseConcurrent) {
1096             boolean removed;
1097             MessageNode first;
1098             final MatchBarrierToken matchBarrierToken = new MatchBarrierToken(token);
1099 
1100             try {
1101                 /* Retain the first element to see if we are currently stuck on a barrier. */
1102                 first = mPriorityQueue.first();
1103             } catch (NoSuchElementException e) {
1104                 /* The queue is empty */
1105                 first = null;
1106             }
1107 
1108             removed = findOrRemoveMessages(null, 0, null, null, 0, matchBarrierToken, true);
1109             if (removed && first != null) {
1110                 Message m = first.mMessage;
1111                 if (m.target == null && m.arg1 == token) {
1112                     /* Wake up next() in case it was sleeping on this barrier. */
1113                     nativeWake(mPtr);
1114                 }
1115             } else if (!removed) {
1116                 throw new IllegalStateException("The specified message queue synchronization "
1117                         + " barrier token has not been posted or has already been removed.");
1118             }
1119             return;
1120         }
1121 
1122         synchronized (this) {
1123             Message prev = null;
1124             Message p = mMessages;
1125             while (p != null && (p.target != null || p.arg1 != token)) {
1126                 prev = p;
1127                 p = p.next;
1128             }
1129             if (p == null) {
1130                 throw new IllegalStateException("The specified message queue synchronization "
1131                         + " barrier token has not been posted or has already been removed.");
1132             }
1133             final boolean needWake;
1134             if (prev != null) {
1135                 prev.next = p.next;
1136                 if (prev.next == null) {
1137                     mLast = prev;
1138                 }
1139                 needWake = false;
1140             } else {
1141                 mMessages = p.next;
1142                 if (mMessages == null) {
1143                     mLast = null;
1144                 }
1145                 needWake = mMessages == null || mMessages.target != null;
1146             }
1147             p.recycleUnchecked();
1148 
1149             // If the loop is quitting then it is already awake.
1150             // We can assume mPtr != 0 when mQuitting is false.
1151             if (needWake && !mQuitting) {
1152                 nativeWake(mPtr);
1153             }
1154         }
1155     }
1156 
enqueueMessage(Message msg, long when)1157     boolean enqueueMessage(Message msg, long when) {
1158         if (msg.target == null) {
1159             throw new IllegalArgumentException("Message must have a target.");
1160         }
1161 
1162         if (mUseConcurrent) {
1163             if (msg.isInUse()) {
1164                 throw new IllegalStateException(msg + " This message is already in use.");
1165             }
1166 
1167             return enqueueMessageUnchecked(msg, when);
1168         }
1169 
1170         synchronized (this) {
1171             if (msg.isInUse()) {
1172                 throw new IllegalStateException(msg + " This message is already in use.");
1173             }
1174 
1175             if (mQuitting) {
1176                 IllegalStateException e = new IllegalStateException(
1177                         msg.target + " sending message to a Handler on a dead thread");
1178                 Log.w(TAG_L, e.getMessage(), e);
1179                 msg.recycle();
1180                 return false;
1181             }
1182 
1183             msg.markInUse();
1184             msg.when = when;
1185             Message p = mMessages;
1186             boolean needWake;
1187             if (p == null || when == 0 || when < p.when) {
1188                 // New head, wake up the event queue if blocked.
1189                 msg.next = p;
1190                 mMessages = msg;
1191                 needWake = mBlocked;
1192                 if (p == null) {
1193                     mLast = mMessages;
1194                 }
1195             } else {
1196                 // Message is to be inserted at tail or middle of queue. Usually we don't have to
1197                 // wake up the event queue unless there is a barrier at the head of the queue and
1198                 // the message is the earliest asynchronous message in the queue.
1199                 needWake = mBlocked && p.target == null && msg.isAsynchronous();
1200 
1201                 // For readability, we split this portion of the function into two blocks based on
1202                 // whether tail tracking is enabled. This has a minor implication for the case
1203                 // where tail tracking is disabled. See the comment below.
1204                 if (Flags.messageQueueTailTracking()) {
1205                     if (when >= mLast.when) {
1206                         needWake = needWake && mAsyncMessageCount == 0;
1207                         msg.next = null;
1208                         mLast.next = msg;
1209                         mLast = msg;
1210                     } else {
1211                         // Inserted within the middle of the queue.
1212                         Message prev;
1213                         for (;;) {
1214                             prev = p;
1215                             p = p.next;
1216                             if (p == null || when < p.when) {
1217                                 break;
1218                             }
1219                             if (needWake && p.isAsynchronous()) {
1220                                 needWake = false;
1221                             }
1222                         }
1223                         if (p == null) {
1224                             /* Inserting at tail of queue */
1225                             mLast = msg;
1226                         }
1227                         msg.next = p; // invariant: p == prev.next
1228                         prev.next = msg;
1229                     }
1230                 } else {
1231                     Message prev;
1232                     for (;;) {
1233                         prev = p;
1234                         p = p.next;
1235                         if (p == null || when < p.when) {
1236                             break;
1237                         }
1238                         if (needWake && p.isAsynchronous()) {
1239                             needWake = false;
1240                         }
1241                     }
1242                     msg.next = p; // invariant: p == prev.next
1243                     prev.next = msg;
1244 
1245                     /*
1246                      * If this block is executing then we have a build without tail tracking -
1247                      * specifically: Flags.messageQueueTailTracking() == false. This is determined
1248                      * at build time so the flag won't change on us during runtime.
1249                      *
1250                      * Since we don't want to pepper the code with extra checks, we only check
1251                      * for tail tracking when we might use mLast. Otherwise, we continue to update
1252                      * mLast as the tail of the list.
1253                      *
1254                      * In this case however we are not maintaining mLast correctly. Since we never
1255                      * use it, this is fine. However, we run the risk of leaking a reference.
1256                      * So set mLast to null in this case to avoid any Message leaks. The other
1257                      * sites will never use the value so we are safe against null pointer derefs.
1258                      */
1259                     mLast = null;
1260                 }
1261             }
1262 
1263             if (msg.isAsynchronous()) {
1264                 mAsyncMessageCount++;
1265             }
1266 
1267             // We can assume mPtr != 0 because mQuitting is false.
1268             if (needWake) {
1269                 nativeWake(mPtr);
1270             }
1271         }
1272         return true;
1273     }
1274 
legacyPeekOrPoll(boolean peek)1275     private Message legacyPeekOrPoll(boolean peek) {
1276         synchronized (this) {
1277             // Try to retrieve the next message.  Return if found.
1278             final long now = SystemClock.uptimeMillis();
1279             Message prevMsg = null;
1280             Message msg = mMessages;
1281             if (msg != null && msg.target == null) {
1282                 // Stalled by a barrier.  Find the next asynchronous message in the queue.
1283                 do {
1284                     prevMsg = msg;
1285                     msg = msg.next;
1286                 } while (msg != null && !msg.isAsynchronous());
1287             }
1288             if (msg != null) {
1289                 if (now >= msg.when) {
1290                     // Got a message.
1291                     mBlocked = false;
1292                     if (peek) {
1293                         return msg;
1294                     }
1295                     if (prevMsg != null) {
1296                         prevMsg.next = msg.next;
1297                         if (prevMsg.next == null) {
1298                             mLast = prevMsg;
1299                         }
1300                     } else {
1301                         mMessages = msg.next;
1302                         if (msg.next == null) {
1303                             mLast = null;
1304                         }
1305                     }
1306                     msg.next = null;
1307                     msg.markInUse();
1308                     if (msg.isAsynchronous()) {
1309                         mAsyncMessageCount--;
1310                     }
1311                     if (TRACE) {
1312                         Trace.setCounter("MQ.Delivered", mMessagesDelivered.incrementAndGet());
1313                     }
1314                     return msg;
1315                 }
1316             }
1317         }
1318         return null;
1319     }
1320 
1321     /**
1322      * Get the timestamp of the next executable message in our priority queue.
1323      * Returns null if there are no messages ready for delivery.
1324      *
1325      * Caller must ensure that this doesn't race 'next' from the Looper thread.
1326      */
1327     @SuppressLint("VisiblySynchronized") // Legacy MessageQueue synchronizes on this
peekWhenForTest()1328     Long peekWhenForTest() {
1329         throwIfNotTest();
1330         Message ret;
1331         if (mUseConcurrent) {
1332             ret = nextMessage(true);
1333         } else {
1334             ret = legacyPeekOrPoll(true);
1335         }
1336         return ret != null ? ret.when : null;
1337     }
1338 
1339     /**
1340      * Return the next executable message in our priority queue.
1341      * Returns null if there are no messages ready for delivery
1342      *
1343      * Caller must ensure that this doesn't race 'next' from the Looper thread.
1344      */
1345     @SuppressLint("VisiblySynchronized") // Legacy MessageQueue synchronizes on this
1346     @Nullable
pollForTest()1347     Message pollForTest() {
1348         throwIfNotTest();
1349         if (mUseConcurrent) {
1350             return nextMessage(false);
1351         } else {
1352             return legacyPeekOrPoll(false);
1353         }
1354     }
1355 
1356     /**
1357      * @return true if we are blocked on a sync barrier
1358      */
isBlockedOnSyncBarrier()1359     boolean isBlockedOnSyncBarrier() {
1360         throwIfNotTest();
1361         if (mUseConcurrent) {
1362             Iterator<MessageNode> queueIter = mPriorityQueue.iterator();
1363             MessageNode queueNode = iterateNext(queueIter);
1364 
1365             if (queueNode.isBarrier()) {
1366                 long now = SystemClock.uptimeMillis();
1367 
1368                 /* Look for a deliverable async node. If one exists we are not blocked. */
1369                 Iterator<MessageNode> asyncQueueIter = mAsyncPriorityQueue.iterator();
1370                 MessageNode asyncNode = iterateNext(asyncQueueIter);
1371                 if (asyncNode != null && now >= asyncNode.getWhen()) {
1372                     return false;
1373                 }
1374                 /*
1375                  * Look for a deliverable sync node. In this case, if one exists we are blocked
1376                  * since the barrier prevents delivery of the Message.
1377                  */
1378                 while (queueNode.isBarrier()) {
1379                     queueNode = iterateNext(queueIter);
1380                 }
1381                 if (queueNode != null && now >= queueNode.getWhen()) {
1382                     return true;
1383                 }
1384 
1385                 return false;
1386             }
1387         } else {
1388             Message msg = mMessages;
1389             if (msg != null && msg.target == null) {
1390                 Message iter = msg;
1391                 /* Look for a deliverable async node */
1392                 do {
1393                     iter = iter.next;
1394                 } while (iter != null && !iter.isAsynchronous());
1395 
1396                 long now = SystemClock.uptimeMillis();
1397                 if (iter != null && now >= iter.when) {
1398                     return false;
1399                 }
1400                 /*
1401                  * Look for a deliverable sync node. In this case, if one exists we are blocked
1402                  * since the barrier prevents delivery of the Message.
1403                  */
1404                 iter = msg;
1405                 do {
1406                     iter = iter.next;
1407                 } while (iter != null && (iter.target == null || iter.isAsynchronous()));
1408 
1409                 if (iter != null && now >= iter.when) {
1410                     return true;
1411                 }
1412                 return false;
1413             }
1414         }
1415         /* No barrier was found. */
1416         return false;
1417     }
1418 
1419     private static final class MatchHandlerWhatAndObject extends MessageCompare {
1420         @Override
compareMessage(MessageNode n, Handler h, int what, Object object, Runnable r, long when)1421         public boolean compareMessage(MessageNode n, Handler h, int what, Object object, Runnable r,
1422                 long when) {
1423             final Message m = n.mMessage;
1424             if (m.target == h && m.what == what && (object == null || m.obj == object)) {
1425                 return true;
1426             }
1427             return false;
1428         }
1429     }
1430     private final MatchHandlerWhatAndObject mMatchHandlerWhatAndObject =
1431             new MatchHandlerWhatAndObject();
hasMessages(Handler h, int what, Object object)1432     boolean hasMessages(Handler h, int what, Object object) {
1433         if (h == null) {
1434             return false;
1435         }
1436         if (mUseConcurrent) {
1437             return findOrRemoveMessages(h, what, object, null, 0, mMatchHandlerWhatAndObject,
1438                     false);
1439         }
1440         synchronized (this) {
1441             Message p = mMessages;
1442             while (p != null) {
1443                 if (p.target == h && p.what == what && (object == null || p.obj == object)) {
1444                     return true;
1445                 }
1446                 p = p.next;
1447             }
1448             return false;
1449         }
1450     }
1451 
1452     private static final class MatchHandlerWhatAndObjectEquals extends MessageCompare {
1453         @Override
compareMessage(MessageNode n, Handler h, int what, Object object, Runnable r, long when)1454         public boolean compareMessage(MessageNode n, Handler h, int what, Object object, Runnable r,
1455                 long when) {
1456             final Message m = n.mMessage;
1457             if (m.target == h && m.what == what && (object == null || object.equals(m.obj))) {
1458                 return true;
1459             }
1460             return false;
1461         }
1462     }
1463     private final MatchHandlerWhatAndObjectEquals mMatchHandlerWhatAndObjectEquals =
1464             new MatchHandlerWhatAndObjectEquals();
hasEqualMessages(Handler h, int what, Object object)1465     boolean hasEqualMessages(Handler h, int what, Object object) {
1466         if (h == null) {
1467             return false;
1468         }
1469         if (mUseConcurrent) {
1470             return findOrRemoveMessages(h, what, object, null, 0, mMatchHandlerWhatAndObjectEquals,
1471                     false);
1472 
1473         }
1474         synchronized (this) {
1475             Message p = mMessages;
1476             while (p != null) {
1477                 if (p.target == h && p.what == what && (object == null || object.equals(p.obj))) {
1478                     return true;
1479                 }
1480                 p = p.next;
1481             }
1482             return false;
1483         }
1484     }
1485 
1486     private static final class MatchHandlerRunnableAndObject extends MessageCompare {
1487         @Override
compareMessage(MessageNode n, Handler h, int what, Object object, Runnable r, long when)1488         public boolean compareMessage(MessageNode n, Handler h, int what, Object object, Runnable r,
1489                 long when) {
1490             final Message m = n.mMessage;
1491             if (m.target == h && m.callback == r && (object == null || m.obj == object)) {
1492                 return true;
1493             }
1494             return false;
1495         }
1496     }
1497     private final MatchHandlerRunnableAndObject mMatchHandlerRunnableAndObject =
1498             new MatchHandlerRunnableAndObject();
1499     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
hasMessages(Handler h, Runnable r, Object object)1500     boolean hasMessages(Handler h, Runnable r, Object object) {
1501         if (h == null) {
1502             return false;
1503         }
1504         if (mUseConcurrent) {
1505             return findOrRemoveMessages(h, -1, object, r, 0, mMatchHandlerRunnableAndObject,
1506                     false);
1507         }
1508 
1509         synchronized (this) {
1510             Message p = mMessages;
1511             while (p != null) {
1512                 if (p.target == h && p.callback == r && (object == null || p.obj == object)) {
1513                     return true;
1514                 }
1515                 p = p.next;
1516             }
1517             return false;
1518         }
1519     }
1520 
1521     private static final class MatchHandler extends MessageCompare {
1522         @Override
compareMessage(MessageNode n, Handler h, int what, Object object, Runnable r, long when)1523         public boolean compareMessage(MessageNode n, Handler h, int what, Object object, Runnable r,
1524                 long when) {
1525             return n.mMessage.target == h;
1526         }
1527     }
1528     private final MatchHandler mMatchHandler = new MatchHandler();
hasMessages(Handler h)1529     boolean hasMessages(Handler h) {
1530         if (h == null) {
1531             return false;
1532         }
1533         if (mUseConcurrent) {
1534             return findOrRemoveMessages(h, -1, null, null, 0, mMatchHandler, false);
1535         }
1536         synchronized (this) {
1537             Message p = mMessages;
1538             while (p != null) {
1539                 if (p.target == h) {
1540                     return true;
1541                 }
1542                 p = p.next;
1543             }
1544             return false;
1545         }
1546     }
1547 
removeMessages(Handler h, int what, Object object)1548     void removeMessages(Handler h, int what, Object object) {
1549         if (h == null) {
1550             return;
1551         }
1552         if (mUseConcurrent) {
1553             findOrRemoveMessages(h, what, object, null, 0, mMatchHandlerWhatAndObject, true);
1554             return;
1555         }
1556         synchronized (this) {
1557             Message p = mMessages;
1558 
1559             // Remove all messages at front.
1560             while (p != null && p.target == h && p.what == what
1561                    && (object == null || p.obj == object)) {
1562                 Message n = p.next;
1563                 mMessages = n;
1564                 if (p.isAsynchronous()) {
1565                     mAsyncMessageCount--;
1566                 }
1567                 p.recycleUnchecked();
1568                 p = n;
1569             }
1570 
1571             if (p == null) {
1572                 mLast = mMessages;
1573             }
1574 
1575             // Remove all messages after front.
1576             while (p != null) {
1577                 Message n = p.next;
1578                 if (n != null) {
1579                     if (n.target == h && n.what == what
1580                             && (object == null || n.obj == object)) {
1581                         Message nn = n.next;
1582                         if (n.isAsynchronous()) {
1583                             mAsyncMessageCount--;
1584                         }
1585                         n.recycleUnchecked();
1586                         p.next = nn;
1587                         if (p.next == null) {
1588                             mLast = p;
1589                         }
1590                         continue;
1591                     }
1592                 }
1593                 p = n;
1594             }
1595         }
1596     }
1597 
removeEqualMessages(Handler h, int what, Object object)1598     void removeEqualMessages(Handler h, int what, Object object) {
1599         if (h == null) {
1600             return;
1601         }
1602 
1603         if (mUseConcurrent) {
1604             findOrRemoveMessages(h, what, object, null, 0, mMatchHandlerWhatAndObjectEquals, true);
1605             return;
1606         }
1607 
1608         synchronized (this) {
1609             Message p = mMessages;
1610 
1611             // Remove all messages at front.
1612             while (p != null && p.target == h && p.what == what
1613                    && (object == null || object.equals(p.obj))) {
1614                 Message n = p.next;
1615                 mMessages = n;
1616                 if (p.isAsynchronous()) {
1617                     mAsyncMessageCount--;
1618                 }
1619                 p.recycleUnchecked();
1620                 p = n;
1621             }
1622 
1623             if (p == null) {
1624                 mLast = mMessages;
1625             }
1626 
1627             // Remove all messages after front.
1628             while (p != null) {
1629                 Message n = p.next;
1630                 if (n != null) {
1631                     if (n.target == h && n.what == what
1632                             && (object == null || object.equals(n.obj))) {
1633                         Message nn = n.next;
1634                         if (n.isAsynchronous()) {
1635                             mAsyncMessageCount--;
1636                         }
1637                         n.recycleUnchecked();
1638                         p.next = nn;
1639                         if (p.next == null) {
1640                             mLast = p;
1641                         }
1642                         continue;
1643                     }
1644                 }
1645                 p = n;
1646             }
1647         }
1648     }
1649 
removeMessages(Handler h, Runnable r, Object object)1650     void removeMessages(Handler h, Runnable r, Object object) {
1651         if (h == null || r == null) {
1652             return;
1653         }
1654 
1655         if (mUseConcurrent) {
1656             findOrRemoveMessages(h, -1, object, r, 0, mMatchHandlerRunnableAndObject, true);
1657             return;
1658         }
1659         synchronized (this) {
1660             Message p = mMessages;
1661 
1662             // Remove all messages at front.
1663             while (p != null && p.target == h && p.callback == r
1664                    && (object == null || p.obj == object)) {
1665                 Message n = p.next;
1666                 mMessages = n;
1667                 if (p.isAsynchronous()) {
1668                     mAsyncMessageCount--;
1669                 }
1670                 p.recycleUnchecked();
1671                 p = n;
1672             }
1673 
1674             if (p == null) {
1675                 mLast = mMessages;
1676             }
1677 
1678             // Remove all messages after front.
1679             while (p != null) {
1680                 Message n = p.next;
1681                 if (n != null) {
1682                     if (n.target == h && n.callback == r
1683                             && (object == null || n.obj == object)) {
1684                         Message nn = n.next;
1685                         if (n.isAsynchronous()) {
1686                             mAsyncMessageCount--;
1687                         }
1688                         n.recycleUnchecked();
1689                         p.next = nn;
1690                         if (p.next == null) {
1691                             mLast = p;
1692                         }
1693                         continue;
1694                     }
1695                 }
1696                 p = n;
1697             }
1698         }
1699     }
1700 
1701     private static final class MatchHandlerRunnableAndObjectEquals extends MessageCompare {
1702         @Override
compareMessage(MessageNode n, Handler h, int what, Object object, Runnable r, long when)1703         public boolean compareMessage(MessageNode n, Handler h, int what, Object object, Runnable r,
1704                 long when) {
1705             final Message m = n.mMessage;
1706             if (m.target == h && m.callback == r && (object == null || object.equals(m.obj))) {
1707                 return true;
1708             }
1709             return false;
1710         }
1711     }
1712     private final MatchHandlerRunnableAndObjectEquals mMatchHandlerRunnableAndObjectEquals =
1713             new MatchHandlerRunnableAndObjectEquals();
removeEqualMessages(Handler h, Runnable r, Object object)1714     void removeEqualMessages(Handler h, Runnable r, Object object) {
1715         if (h == null || r == null) {
1716             return;
1717         }
1718 
1719         if (mUseConcurrent) {
1720             findOrRemoveMessages(h, -1, object, r, 0, mMatchHandlerRunnableAndObjectEquals, true);
1721             return;
1722         }
1723         synchronized (this) {
1724             Message p = mMessages;
1725 
1726             // Remove all messages at front.
1727             while (p != null && p.target == h && p.callback == r
1728                    && (object == null || object.equals(p.obj))) {
1729                 Message n = p.next;
1730                 mMessages = n;
1731                 if (p.isAsynchronous()) {
1732                     mAsyncMessageCount--;
1733                 }
1734                 p.recycleUnchecked();
1735                 p = n;
1736             }
1737 
1738             if (p == null) {
1739                 mLast = mMessages;
1740             }
1741 
1742             // Remove all messages after front.
1743             while (p != null) {
1744                 Message n = p.next;
1745                 if (n != null) {
1746                     if (n.target == h && n.callback == r
1747                             && (object == null || object.equals(n.obj))) {
1748                         Message nn = n.next;
1749                         if (n.isAsynchronous()) {
1750                             mAsyncMessageCount--;
1751                         }
1752                         n.recycleUnchecked();
1753                         p.next = nn;
1754                         if (p.next == null) {
1755                             mLast = p;
1756                         }
1757                         continue;
1758                     }
1759                 }
1760                 p = n;
1761             }
1762         }
1763     }
1764 
1765     private static final class MatchHandlerAndObject extends MessageCompare {
1766         @Override
compareMessage(MessageNode n, Handler h, int what, Object object, Runnable r, long when)1767         public boolean compareMessage(MessageNode n, Handler h, int what, Object object, Runnable r,
1768                 long when) {
1769             final Message m = n.mMessage;
1770             if (m.target == h && (object == null || m.obj == object)) {
1771                 return true;
1772             }
1773             return false;
1774         }
1775     }
1776     private final MatchHandlerAndObject mMatchHandlerAndObject = new MatchHandlerAndObject();
removeCallbacksAndMessages(Handler h, Object object)1777     void removeCallbacksAndMessages(Handler h, Object object) {
1778         if (h == null) {
1779             return;
1780         }
1781 
1782         if (mUseConcurrent) {
1783             findOrRemoveMessages(h, -1, object, null, 0, mMatchHandlerAndObject, true);
1784             return;
1785         }
1786         synchronized (this) {
1787             Message p = mMessages;
1788 
1789             // Remove all messages at front.
1790             while (p != null && p.target == h
1791                     && (object == null || p.obj == object)) {
1792                 Message n = p.next;
1793                 mMessages = n;
1794                 if (p.isAsynchronous()) {
1795                     mAsyncMessageCount--;
1796                 }
1797                 p.recycleUnchecked();
1798                 p = n;
1799             }
1800 
1801             if (p == null) {
1802                 mLast = mMessages;
1803             }
1804 
1805             // Remove all messages after front.
1806             while (p != null) {
1807                 Message n = p.next;
1808                 if (n != null) {
1809                     if (n.target == h && (object == null || n.obj == object)) {
1810                         Message nn = n.next;
1811                         if (n.isAsynchronous()) {
1812                             mAsyncMessageCount--;
1813                         }
1814                         n.recycleUnchecked();
1815                         p.next = nn;
1816                         if (p.next == null) {
1817                             mLast = p;
1818                         }
1819                         continue;
1820                     }
1821                 }
1822                 p = n;
1823             }
1824         }
1825     }
1826 
1827     private static final class MatchHandlerAndObjectEquals extends MessageCompare {
1828         @Override
compareMessage(MessageNode n, Handler h, int what, Object object, Runnable r, long when)1829         public boolean compareMessage(MessageNode n, Handler h, int what, Object object, Runnable r,
1830                 long when) {
1831             final Message m = n.mMessage;
1832             if (m.target == h && (object == null || object.equals(m.obj))) {
1833                 return true;
1834             }
1835             return false;
1836         }
1837     }
1838     private final MatchHandlerAndObjectEquals mMatchHandlerAndObjectEquals =
1839             new MatchHandlerAndObjectEquals();
removeCallbacksAndEqualMessages(Handler h, Object object)1840     void removeCallbacksAndEqualMessages(Handler h, Object object) {
1841         if (h == null) {
1842             return;
1843         }
1844 
1845         if (mUseConcurrent) {
1846             findOrRemoveMessages(h, -1, object, null, 0, mMatchHandlerAndObjectEquals, true);
1847             return;
1848         }
1849         synchronized (this) {
1850             Message p = mMessages;
1851 
1852             // Remove all messages at front.
1853             while (p != null && p.target == h
1854                     && (object == null || object.equals(p.obj))) {
1855                 Message n = p.next;
1856                 mMessages = n;
1857                 if (p.isAsynchronous()) {
1858                     mAsyncMessageCount--;
1859                 }
1860                 p.recycleUnchecked();
1861                 p = n;
1862             }
1863 
1864             if (p == null) {
1865                 mLast = mMessages;
1866             }
1867 
1868             // Remove all messages after front.
1869             while (p != null) {
1870                 Message n = p.next;
1871                 if (n != null) {
1872                     if (n.target == h && (object == null || object.equals(n.obj))) {
1873                         Message nn = n.next;
1874                         if (n.isAsynchronous()) {
1875                             mAsyncMessageCount--;
1876                         }
1877                         n.recycleUnchecked();
1878                         p.next = nn;
1879                         if (p.next == null) {
1880                             mLast = p;
1881                         }
1882                         continue;
1883                     }
1884                 }
1885                 p = n;
1886             }
1887         }
1888     }
1889 
removeAllMessagesLocked()1890     private void removeAllMessagesLocked() {
1891         Message p = mMessages;
1892         while (p != null) {
1893             Message n = p.next;
1894             p.recycleUnchecked();
1895             p = n;
1896         }
1897         mMessages = null;
1898         mLast = null;
1899         mAsyncMessageCount = 0;
1900     }
1901 
removeAllFutureMessagesLocked()1902     private void removeAllFutureMessagesLocked() {
1903         final long now = SystemClock.uptimeMillis();
1904         Message p = mMessages;
1905         if (p != null) {
1906             if (p.when > now) {
1907                 removeAllMessagesLocked();
1908             } else {
1909                 Message n;
1910                 for (;;) {
1911                     n = p.next;
1912                     if (n == null) {
1913                         return;
1914                     }
1915                     if (n.when > now) {
1916                         break;
1917                     }
1918                     p = n;
1919                 }
1920                 p.next = null;
1921                 mLast = p;
1922 
1923                 do {
1924                     p = n;
1925                     n = p.next;
1926                     if (p.isAsynchronous()) {
1927                         mAsyncMessageCount--;
1928                     }
1929                     p.recycleUnchecked();
1930                 } while (n != null);
1931             }
1932         }
1933     }
1934 
1935     private static final class MatchAllMessages extends MessageCompare {
1936         @Override
compareMessage(MessageNode n, Handler h, int what, Object object, Runnable r, long when)1937         public boolean compareMessage(MessageNode n, Handler h, int what, Object object, Runnable r,
1938                 long when) {
1939             return true;
1940         }
1941     }
1942     private final MatchAllMessages mMatchAllMessages = new MatchAllMessages();
removeAllMessages()1943     private void removeAllMessages() {
1944         findOrRemoveMessages(null, -1, null, null, 0, mMatchAllMessages, true);
1945     }
1946 
1947     private static final class MatchAllFutureMessages extends MessageCompare {
1948         @Override
compareMessage(MessageNode n, Handler h, int what, Object object, Runnable r, long when)1949         public boolean compareMessage(MessageNode n, Handler h, int what, Object object, Runnable r,
1950                 long when) {
1951             final Message m = n.mMessage;
1952                     if (m.when > when) {
1953                 return true;
1954             }
1955             return false;
1956         }
1957     }
1958     private final MatchAllFutureMessages mMatchAllFutureMessages = new MatchAllFutureMessages();
removeAllFutureMessages()1959     private void removeAllFutureMessages() {
1960         findOrRemoveMessages(null, -1, null, null, SystemClock.uptimeMillis(),
1961                 mMatchAllFutureMessages, true);
1962     }
1963 
1964     @NeverCompile
printPriorityQueueNodes()1965     private void printPriorityQueueNodes() {
1966         Iterator<MessageNode> iterator = mPriorityQueue.iterator();
1967 
1968         Log.d(TAG_C, "* Dump priority queue");
1969         while (iterator.hasNext()) {
1970             MessageNode msgNode = iterator.next();
1971             Log.d(TAG_C, "** MessageNode what: " + msgNode.mMessage.what + " when "
1972                     + msgNode.mMessage.when + " seq: " + msgNode.mInsertSeq);
1973         }
1974     }
1975 
1976     @NeverCompile
dumpPriorityQueue(ConcurrentSkipListSet<MessageNode> queue, Printer pw, String prefix, Handler h, int n)1977     private int dumpPriorityQueue(ConcurrentSkipListSet<MessageNode> queue, Printer pw,
1978             String prefix, Handler h, int n) {
1979         int count = 0;
1980         long now = SystemClock.uptimeMillis();
1981 
1982         for (MessageNode msgNode : queue) {
1983             Message msg = msgNode.mMessage;
1984             if (h == null || h == msg.target) {
1985                 pw.println(prefix + "Message " + (n + count) + ": " + msg.toString(now));
1986             }
1987             count++;
1988         }
1989         return count;
1990     }
1991 
1992     @NeverCompile
dump(Printer pw, String prefix, Handler h)1993     void dump(Printer pw, String prefix, Handler h) {
1994         if (mUseConcurrent) {
1995             long now = SystemClock.uptimeMillis();
1996             int n = 0;
1997 
1998             pw.println(prefix + "(MessageQueue is using Concurrent implementation)");
1999 
2000             StackNode node = (StackNode) sState.getVolatile(this);
2001             while (node != null) {
2002                 if (node.isMessageNode()) {
2003                     Message msg = ((MessageNode) node).mMessage;
2004                     if (h == null || h == msg.target) {
2005                         pw.println(prefix + "Message " + n + ": " + msg.toString(now));
2006                     }
2007                     node = ((MessageNode) node).mNext;
2008                 } else {
2009                     pw.println(prefix + "State: " + node);
2010                     node = null;
2011                 }
2012                 n++;
2013             }
2014 
2015             pw.println(prefix + "PriorityQueue Messages: ");
2016             n += dumpPriorityQueue(mPriorityQueue, pw, prefix, h, n);
2017             pw.println(prefix + "AsyncPriorityQueue Messages: ");
2018             n += dumpPriorityQueue(mAsyncPriorityQueue, pw, prefix, h, n);
2019 
2020             pw.println(prefix + "(Total messages: " + n + ", polling=" + isPolling()
2021                     + ", quitting=" + (boolean) sQuitting.getVolatile(this) + ")");
2022             return;
2023         }
2024 
2025         synchronized (this) {
2026             pw.println(prefix + "(MessageQueue is using Legacy implementation)");
2027             long now = SystemClock.uptimeMillis();
2028             int n = 0;
2029             for (Message msg = mMessages; msg != null; msg = msg.next) {
2030                 if (h == null || h == msg.target) {
2031                     pw.println(prefix + "Message " + n + ": " + msg.toString(now));
2032                 }
2033                 n++;
2034             }
2035             pw.println(prefix + "(Total messages: " + n + ", polling=" + isPollingLocked()
2036                     + ", quitting=" + mQuitting + ")");
2037         }
2038     }
2039 
2040     @NeverCompile
dumpPriorityQueue(ConcurrentSkipListSet<MessageNode> queue, ProtoOutputStream proto)2041     private int dumpPriorityQueue(ConcurrentSkipListSet<MessageNode> queue,
2042             ProtoOutputStream proto) {
2043         int count = 0;
2044 
2045         for (MessageNode msgNode : queue) {
2046             Message msg = msgNode.mMessage;
2047             msg.dumpDebug(proto, MessageQueueProto.MESSAGES);
2048             count++;
2049         }
2050         return count;
2051     }
2052 
2053     @NeverCompile
dumpDebug(ProtoOutputStream proto, long fieldId)2054     void dumpDebug(ProtoOutputStream proto, long fieldId) {
2055         if (mUseConcurrent) {
2056             final long messageQueueToken = proto.start(fieldId);
2057 
2058             StackNode node = (StackNode) sState.getVolatile(this);
2059             while (node.isMessageNode()) {
2060                 Message msg = ((MessageNode) node).mMessage;
2061                 msg.dumpDebug(proto, MessageQueueProto.MESSAGES);
2062                 node = ((MessageNode) node).mNext;
2063             }
2064 
2065             dumpPriorityQueue(mPriorityQueue, proto);
2066             dumpPriorityQueue(mAsyncPriorityQueue, proto);
2067 
2068             proto.write(MessageQueueProto.IS_POLLING_LOCKED, isPolling());
2069             proto.write(MessageQueueProto.IS_QUITTING, (boolean) sQuitting.getVolatile(this));
2070             proto.end(messageQueueToken);
2071             return;
2072         }
2073 
2074         final long messageQueueToken = proto.start(fieldId);
2075         synchronized (this) {
2076             for (Message msg = mMessages; msg != null; msg = msg.next) {
2077                 msg.dumpDebug(proto, MessageQueueProto.MESSAGES);
2078             }
2079             proto.write(MessageQueueProto.IS_POLLING_LOCKED, isPollingLocked());
2080             proto.write(MessageQueueProto.IS_QUITTING, mQuitting);
2081         }
2082         proto.end(messageQueueToken);
2083     }
2084 
2085     /**
2086      * Callback interface for discovering when a thread is going to block
2087      * waiting for more messages.
2088      */
2089     public static interface IdleHandler {
2090         /**
2091          * Called when the message queue has run out of messages and will now
2092          * wait for more.  Return true to keep your idle handler active, false
2093          * to have it removed.  This may be called if there are still messages
2094          * pending in the queue, but they are all scheduled to be dispatched
2095          * after the current time.
2096          */
queueIdle()2097         boolean queueIdle();
2098     }
2099 
2100     /**
2101      * A listener which is invoked when file descriptor related events occur.
2102      */
2103     public interface OnFileDescriptorEventListener {
2104         /**
2105          * File descriptor event: Indicates that the file descriptor is ready for input
2106          * operations, such as reading.
2107          * <p>
2108          * The listener should read all available data from the file descriptor
2109          * then return <code>true</code> to keep the listener active or <code>false</code>
2110          * to remove the listener.
2111          * </p><p>
2112          * In the case of a socket, this event may be generated to indicate
2113          * that there is at least one incoming connection that the listener
2114          * should accept.
2115          * </p><p>
2116          * This event will only be generated if the {@link #EVENT_INPUT} event mask was
2117          * specified when the listener was added.
2118          * </p>
2119          */
2120         public static final int EVENT_INPUT = 1 << 0;
2121 
2122         /**
2123          * File descriptor event: Indicates that the file descriptor is ready for output
2124          * operations, such as writing.
2125          * <p>
2126          * The listener should write as much data as it needs.  If it could not
2127          * write everything at once, then it should return <code>true</code> to
2128          * keep the listener active.  Otherwise, it should return <code>false</code>
2129          * to remove the listener then re-register it later when it needs to write
2130          * something else.
2131          * </p><p>
2132          * This event will only be generated if the {@link #EVENT_OUTPUT} event mask was
2133          * specified when the listener was added.
2134          * </p>
2135          */
2136         public static final int EVENT_OUTPUT = 1 << 1;
2137 
2138         /**
2139          * File descriptor event: Indicates that the file descriptor encountered a
2140          * fatal error.
2141          * <p>
2142          * File descriptor errors can occur for various reasons.  One common error
2143          * is when the remote peer of a socket or pipe closes its end of the connection.
2144          * </p><p>
2145          * This event may be generated at any time regardless of whether the
2146          * {@link #EVENT_ERROR} event mask was specified when the listener was added.
2147          * </p>
2148          */
2149         public static final int EVENT_ERROR = 1 << 2;
2150 
2151         /** @hide */
2152         @Retention(RetentionPolicy.SOURCE)
2153         @IntDef(flag = true, prefix = { "EVENT_" }, value = {
2154                 EVENT_INPUT,
2155                 EVENT_OUTPUT,
2156                 EVENT_ERROR
2157         })
2158         public @interface Events {}
2159 
2160         /**
2161          * Called when a file descriptor receives events.
2162          *
2163          * @param fd The file descriptor.
2164          * @param events The set of events that occurred: a combination of the
2165          * {@link #EVENT_INPUT}, {@link #EVENT_OUTPUT}, and {@link #EVENT_ERROR} event masks.
2166          * @return The new set of events to watch, or 0 to unregister the listener.
2167          *
2168          * @see #EVENT_INPUT
2169          * @see #EVENT_OUTPUT
2170          * @see #EVENT_ERROR
2171          */
onFileDescriptorEvents(@onNull FileDescriptor fd, @Events int events)2172         @Events int onFileDescriptorEvents(@NonNull FileDescriptor fd, @Events int events);
2173     }
2174 
2175     private static final class FileDescriptorRecord {
2176         public final FileDescriptor mDescriptor;
2177         public int mEvents;
2178         public OnFileDescriptorEventListener mListener;
2179         public int mSeq;
2180 
FileDescriptorRecord(FileDescriptor descriptor, int events, OnFileDescriptorEventListener listener)2181         public FileDescriptorRecord(FileDescriptor descriptor,
2182                 int events, OnFileDescriptorEventListener listener) {
2183             mDescriptor = descriptor;
2184             mEvents = events;
2185             mListener = listener;
2186         }
2187     }
2188 
2189     /**
2190      * ConcurrentMessageQueue specific classes methods and variables
2191      */
2192     /* Helper to choose the correct queue to insert into. */
insertIntoPriorityQueue(MessageNode msgNode)2193     private void insertIntoPriorityQueue(MessageNode msgNode) {
2194         if (msgNode.isAsync()) {
2195             mAsyncPriorityQueue.add(msgNode);
2196         } else {
2197             mPriorityQueue.add(msgNode);
2198         }
2199     }
2200 
removeFromPriorityQueue(MessageNode msgNode)2201     private boolean removeFromPriorityQueue(MessageNode msgNode) {
2202         if (msgNode.isAsync()) {
2203             return mAsyncPriorityQueue.remove(msgNode);
2204         } else {
2205             return mPriorityQueue.remove(msgNode);
2206         }
2207     }
2208 
pickEarliestNode(MessageNode nodeA, MessageNode nodeB)2209     private MessageNode pickEarliestNode(MessageNode nodeA, MessageNode nodeB) {
2210         if (nodeA != null && nodeB != null) {
2211             if (nodeA.compareTo(nodeB) < 0) {
2212                 return nodeA;
2213             }
2214             return nodeB;
2215         }
2216 
2217         return nodeA != null ? nodeA : nodeB;
2218     }
2219 
iterateNext(Iterator<MessageNode> iter)2220     private MessageNode iterateNext(Iterator<MessageNode> iter) {
2221         if (iter.hasNext()) {
2222             try {
2223                 return iter.next();
2224             } catch (NoSuchElementException e) {
2225                 /* The queue is empty - this can happen if we race with remove */
2226             }
2227         }
2228         return null;
2229     }
2230 
2231     /* Move any non-cancelled messages into the priority queue */
drainStack(StackNode oldTop)2232     private void drainStack(StackNode oldTop) {
2233         while (oldTop.isMessageNode()) {
2234             MessageNode oldTopMessageNode = (MessageNode) oldTop;
2235             if (oldTopMessageNode.removeFromStack()) {
2236                 insertIntoPriorityQueue(oldTopMessageNode);
2237             }
2238             MessageNode inserted = oldTopMessageNode;
2239             oldTop = oldTopMessageNode.mNext;
2240             /*
2241              * removeMessages can walk this list while we are consuming it.
2242              * Set our next pointer to null *after* we add the message to our
2243              * priority queue. This way removeMessages() will always find the
2244              * message, either in our list or in the priority queue.
2245              */
2246             inserted.mNext = null;
2247         }
2248     }
2249 
2250     /* Set the stack state to Active, return a list of nodes to walk. */
swapAndSetStackStateActive()2251     private StackNode swapAndSetStackStateActive() {
2252         while (true) {
2253             /* Set stack state to Active, get node list to walk later */
2254             StackNode current = (StackNode) sState.getVolatile(this);
2255             if (current == sStackStateActive
2256                     || sState.compareAndSet(this, current, sStackStateActive)) {
2257                 return current;
2258             }
2259         }
2260     }
getStateNode(StackNode node)2261     private StateNode getStateNode(StackNode node) {
2262         if (node.isMessageNode()) {
2263             return ((MessageNode) node).mBottomOfStack;
2264         }
2265         return (StateNode) node;
2266     }
2267 
waitForDrainCompleted()2268     private void waitForDrainCompleted() {
2269         mDrainingLock.lock();
2270         while (mNextIsDrainingStack) {
2271             mDrainCompleted.awaitUninterruptibly();
2272         }
2273         mDrainingLock.unlock();
2274     }
2275 
2276     @IntDef(value = {
2277         STACK_NODE_MESSAGE,
2278         STACK_NODE_ACTIVE,
2279         STACK_NODE_PARKED,
2280         STACK_NODE_TIMEDPARK})
2281     @Retention(RetentionPolicy.SOURCE)
2282     private @interface StackNodeType {}
2283 
2284     /*
2285      * Stack node types. STACK_NODE_MESSAGE indicates a node containing a message.
2286      * The other types indicate what state our Looper thread is in. The bottom of
2287      * the stack is always a single state node. Message nodes are added on top.
2288      */
2289     private static final int STACK_NODE_MESSAGE = 0;
2290     /*
2291      * Active state indicates that next() is processing messages
2292      */
2293     private static final int STACK_NODE_ACTIVE = 1;
2294     /*
2295      * Parked state indicates that the Looper thread is sleeping indefinitely (nothing to deliver)
2296      */
2297     private static final int STACK_NODE_PARKED = 2;
2298     /*
2299      * Timed Park state indicates that the Looper thread is sleeping, waiting for a message
2300      * deadline
2301      */
2302     private static final int STACK_NODE_TIMEDPARK = 3;
2303 
2304     /* Describes a node in the Treiber stack */
2305     static class StackNode {
2306         @StackNodeType
2307         private final int mType;
2308 
StackNode(@tackNodeType int type)2309         StackNode(@StackNodeType int type) {
2310             mType = type;
2311         }
2312 
2313         @StackNodeType
getNodeType()2314         final int getNodeType() {
2315             return mType;
2316         }
2317 
isMessageNode()2318         final boolean isMessageNode() {
2319             return mType == STACK_NODE_MESSAGE;
2320         }
2321     }
2322 
2323     static final class MessageNode extends StackNode implements Comparable<MessageNode> {
2324         private final Message mMessage;
2325         volatile StackNode mNext;
2326         StateNode mBottomOfStack;
2327         boolean mWokeUp;
2328         final long mInsertSeq;
2329         private static final VarHandle sRemovedFromStack;
2330         private volatile boolean mRemovedFromStackValue;
2331         static {
2332             try {
2333                 MethodHandles.Lookup l = MethodHandles.lookup();
2334                 sRemovedFromStack = l.findVarHandle(MessageQueue.MessageNode.class,
2335                         "mRemovedFromStackValue", boolean.class);
2336             } catch (Exception e) {
2337                 Log.wtf(TAG_C, "VarHandle lookup failed with exception: " + e);
2338                 throw new ExceptionInInitializerError(e);
2339             }
2340         }
2341 
MessageNode(@onNull Message message, long insertSeq)2342         MessageNode(@NonNull Message message, long insertSeq) {
2343             super(STACK_NODE_MESSAGE);
2344             mMessage = message;
2345             mInsertSeq = insertSeq;
2346         }
2347 
getWhen()2348         long getWhen() {
2349             return mMessage.when;
2350         }
2351 
isRemovedFromStack()2352         boolean isRemovedFromStack() {
2353             return mRemovedFromStackValue;
2354         }
2355 
removeFromStack()2356         boolean removeFromStack() {
2357             return sRemovedFromStack.compareAndSet(this, false, true);
2358         }
2359 
isAsync()2360         boolean isAsync() {
2361             return mMessage.isAsynchronous();
2362         }
2363 
isBarrier()2364         boolean isBarrier() {
2365             return mMessage.target == null;
2366         }
2367 
2368         @Override
compareTo(@onNull MessageNode messageNode)2369         public int compareTo(@NonNull MessageNode messageNode) {
2370             Message other = messageNode.mMessage;
2371 
2372             int compared = Long.compare(mMessage.when, other.when);
2373             if (compared == 0) {
2374                 compared = Long.compare(mInsertSeq, messageNode.mInsertSeq);
2375             }
2376             return compared;
2377         }
2378     }
2379 
2380     static class StateNode extends StackNode {
StateNode(int type)2381         StateNode(int type) {
2382             super(type);
2383         }
2384     }
2385 
2386     static final class TimedParkStateNode extends StateNode {
2387         long mWhenToWake;
2388 
TimedParkStateNode()2389         TimedParkStateNode() {
2390             super(STACK_NODE_TIMEDPARK);
2391         }
2392     }
2393 
2394     private static final StateNode sStackStateActive = new StateNode(STACK_NODE_ACTIVE);
2395     private static final StateNode sStackStateParked = new StateNode(STACK_NODE_PARKED);
2396     private final TimedParkStateNode mStackStateTimedPark = new TimedParkStateNode();
2397 
2398     /* This is the top of our treiber stack. */
2399     private static final VarHandle sState;
2400     static {
2401         try {
2402             MethodHandles.Lookup l = MethodHandles.lookup();
2403             sState = l.findVarHandle(MessageQueue.class, "mStateValue",
2404                     MessageQueue.StackNode.class);
2405         } catch (Exception e) {
2406             Log.wtf(TAG_C, "VarHandle lookup failed with exception: " + e);
2407             throw new ExceptionInInitializerError(e);
2408         }
2409     }
2410 
2411     private volatile StackNode mStateValue = sStackStateParked;
2412     private final ConcurrentSkipListSet<MessageNode> mPriorityQueue =
2413             new ConcurrentSkipListSet<MessageNode>();
2414     private final ConcurrentSkipListSet<MessageNode> mAsyncPriorityQueue =
2415             new ConcurrentSkipListSet<MessageNode>();
2416 
2417     /*
2418      * This helps us ensure that messages with the same timestamp are inserted in FIFO order.
2419      * Increments on each insert, starting at 0. MessageNode.compareTo() will compare sequences
2420      * when delivery timestamps are identical.
2421      */
2422     private static final VarHandle sNextInsertSeq;
2423     private volatile long mNextInsertSeqValue = 0;
2424     /*
2425      * The exception to the FIFO order rule is sendMessageAtFrontOfQueue().
2426      * Those messages must be in LIFO order.
2427      * Decrements on each front of queue insert.
2428      */
2429     private static final VarHandle sNextFrontInsertSeq;
2430     private volatile long mNextFrontInsertSeqValue = -1;
2431     static {
2432         try {
2433             MethodHandles.Lookup l = MethodHandles.lookup();
2434             sNextInsertSeq = l.findVarHandle(MessageQueue.class, "mNextInsertSeqValue",
2435                     long.class);
2436             sNextFrontInsertSeq = l.findVarHandle(MessageQueue.class, "mNextFrontInsertSeqValue",
2437                     long.class);
2438         } catch (Exception e) {
2439             Log.wtf(TAG_C, "VarHandle lookup failed with exception: " + e);
2440             throw new ExceptionInInitializerError(e);
2441         }
2442 
2443     }
2444 
2445     /*
2446      * Tracks the number of queued and cancelled messages in our stack.
2447      *
2448      * On item cancellation, determine whether to wake next() to flush tombstoned messages.
2449      * We track queued and cancelled counts as two ints packed into a single long.
2450      */
2451     private static final class MessageCounts {
2452         private static VarHandle sCounts;
2453         private volatile long mCountsValue = 0;
2454         static {
2455             try {
2456                 MethodHandles.Lookup l = MethodHandles.lookup();
2457                 sCounts = l.findVarHandle(MessageQueue.MessageCounts.class, "mCountsValue",
2458                         long.class);
2459             } catch (Exception e) {
2460                 Log.wtf(TAG_C, "VarHandle lookup failed with exception: " + e);
2461                 throw new ExceptionInInitializerError(e);
2462             }
2463         }
2464 
2465         /* We use a special value to indicate when next() has been woken for flush. */
2466         private static final long AWAKE = Long.MAX_VALUE;
2467         /*
2468          * Minimum number of messages in the stack which we need before we consider flushing
2469          * tombstoned items.
2470          */
2471         private static final int MESSAGE_FLUSH_THRESHOLD = 10;
2472 
numQueued(long val)2473         private static int numQueued(long val) {
2474             return (int) (val >>> Integer.SIZE);
2475         }
2476 
numCancelled(long val)2477         private static int numCancelled(long val) {
2478             return (int) val;
2479         }
2480 
combineCounts(int queued, int cancelled)2481         private static long combineCounts(int queued, int cancelled) {
2482             return ((long) queued << Integer.SIZE) | (long) cancelled;
2483         }
2484 
incrementQueued()2485         public void incrementQueued() {
2486             while (true) {
2487                 long oldVal = mCountsValue;
2488                 int queued = numQueued(oldVal);
2489                 int cancelled = numCancelled(oldVal);
2490                 /* Use Math.max() to avoid overflow of queued count */
2491                 long newVal = combineCounts(Math.max(queued + 1, queued), cancelled);
2492 
2493                 /* Don't overwrite 'AWAKE' state */
2494                 if (oldVal == AWAKE || sCounts.compareAndSet(this, oldVal, newVal)) {
2495                     break;
2496                 }
2497             }
2498         }
2499 
incrementCancelled()2500         public boolean incrementCancelled() {
2501             while (true) {
2502                 long oldVal = mCountsValue;
2503                 if (oldVal == AWAKE) {
2504                     return false;
2505                 }
2506                 int queued = numQueued(oldVal);
2507                 int cancelled = numCancelled(oldVal);
2508                 boolean needsPurge = queued > MESSAGE_FLUSH_THRESHOLD
2509                         && (queued >> 1) < cancelled;
2510                 long newVal;
2511                 if (needsPurge) {
2512                     newVal = AWAKE;
2513                 } else {
2514                     newVal = combineCounts(queued,
2515                             Math.max(cancelled + 1, cancelled));
2516                 }
2517 
2518                 if (sCounts.compareAndSet(this, oldVal, newVal)) {
2519                     return needsPurge;
2520                 }
2521             }
2522         }
2523 
2524         public void clearCounts() {
2525             mCountsValue = 0;
2526         }
2527     }
2528 
2529     private final MessageCounts mMessageCounts = new MessageCounts();
2530 
2531     private final Object mIdleHandlersLock = new Object();
2532     private final Object mFileDescriptorRecordsLock = new Object();
2533 
2534     private static final VarHandle sQuitting;
2535     private boolean mQuittingValue = false;
2536     static {
2537         try {
2538             MethodHandles.Lookup l = MethodHandles.lookup();
2539             sQuitting = l.findVarHandle(MessageQueue.class, "mQuittingValue", boolean.class);
2540         } catch (Exception e) {
2541             Log.wtf(TAG_C, "VarHandle lookup failed with exception: " + e);
2542             throw new ExceptionInInitializerError(e);
2543         }
2544     }
2545 
2546     // The next barrier token.
2547     // Barriers are indicated by messages with a null target whose arg1 field carries the token.
2548     private final AtomicInteger mNextBarrierTokenAtomic = new AtomicInteger(1);
2549 
2550     // Must retain this for compatibility reasons.
2551     @UnsupportedAppUsage
2552     private int mNextBarrierToken;
2553 
2554     /* Protects mNextIsDrainingStack */
2555     private final ReentrantLock mDrainingLock = new ReentrantLock();
2556     private boolean mNextIsDrainingStack = false;
2557     private final Condition mDrainCompleted = mDrainingLock.newCondition();
2558 
2559     private boolean enqueueMessageUnchecked(@NonNull Message msg, long when) {
2560         if ((boolean) sQuitting.getVolatile(this)) {
2561             IllegalStateException e = new IllegalStateException(
2562                     msg.target + " sending message to a Handler on a dead thread");
2563             Log.w(TAG_C, e.getMessage(), e);
2564             msg.recycleUnchecked();
2565             return false;
2566         }
2567 
2568         long seq = when != 0 ? ((long) sNextInsertSeq.getAndAdd(this, 1L) + 1L)
2569                 : ((long) sNextFrontInsertSeq.getAndAdd(this, -1L) - 1L);
2570         /* TODO: Add a MessageNode member to Message so we can avoid this allocation */
2571         MessageNode node = new MessageNode(msg, seq);
2572         msg.when = when;
2573         msg.markInUse();
2574 
2575         if (DEBUG) {
2576             Log.d(TAG_C, "Insert message what: " + msg.what + " when: " + msg.when + " seq: "
2577                     + node.mInsertSeq + " barrier: " + node.isBarrier() + " async: "
2578                     + node.isAsync() + " now: " + SystemClock.uptimeMillis());
2579         }
2580 
2581         final Looper myLooper = Looper.myLooper();
2582         /* If we are running on the looper thread we can add directly to the priority queue */
2583         if (myLooper != null && myLooper.getQueue() == this) {
2584             node.removeFromStack();
2585             insertIntoPriorityQueue(node);
2586             /*
2587              * We still need to do this even though we are the current thread,
2588              * otherwise next() may sleep indefinitely.
2589              */
2590             if (!mMessageDirectlyQueued) {
2591                 mMessageDirectlyQueued = true;
2592                 nativeWake(mPtr);
2593             }
2594             return true;
2595         }
2596 
2597         while (true) {
2598             StackNode old = (StackNode) sState.getVolatile(this);
2599             boolean wakeNeeded;
2600             boolean inactive;
2601 
2602             node.mNext = old;
2603             switch (old.getNodeType()) {
2604                 case STACK_NODE_ACTIVE:
2605                     /*
2606                      * The worker thread is currently active and will process any elements added to
2607                      * the stack before parking again.
2608                      */
2609                     node.mBottomOfStack = (StateNode) old;
2610                     inactive = false;
2611                     node.mWokeUp = true;
2612                     wakeNeeded = false;
2613                     break;
2614 
2615                 case STACK_NODE_PARKED:
2616                     node.mBottomOfStack = (StateNode) old;
2617                     inactive = true;
2618                     node.mWokeUp = true;
2619                     wakeNeeded = true;
2620                     break;
2621 
2622                 case STACK_NODE_TIMEDPARK:
2623                     node.mBottomOfStack = (StateNode) old;
2624                     inactive = true;
2625                     wakeNeeded = mStackStateTimedPark.mWhenToWake >= node.getWhen();
2626                     node.mWokeUp = wakeNeeded;
2627                     break;
2628 
2629                 default:
2630                     MessageNode oldMessage = (MessageNode) old;
2631 
2632                     node.mBottomOfStack = oldMessage.mBottomOfStack;
2633                     int bottomType = node.mBottomOfStack.getNodeType();
2634                     inactive = bottomType >= STACK_NODE_PARKED;
2635                     wakeNeeded = (bottomType == STACK_NODE_TIMEDPARK
2636                             && mStackStateTimedPark.mWhenToWake >= node.getWhen()
2637                             && !oldMessage.mWokeUp);
2638                     node.mWokeUp = oldMessage.mWokeUp || wakeNeeded;
2639                     break;
2640             }
2641             if (sState.compareAndSet(this, old, node)) {
2642                 if (inactive) {
2643                     if (wakeNeeded) {
2644                         nativeWake(mPtr);
2645                     } else {
2646                         mMessageCounts.incrementQueued();
2647                     }
2648                 }
2649                 return true;
2650             }
2651         }
2652     }
2653 
2654     /*
2655      * This class is used to find matches for hasMessages() and removeMessages()
2656      */
2657     private abstract static class MessageCompare {
compareMessage(MessageNode n, Handler h, int what, Object object, Runnable r, long when)2658         public abstract boolean compareMessage(MessageNode n, Handler h, int what, Object object,
2659                 Runnable r, long when);
2660     }
2661 
stackHasMessages(Handler h, int what, Object object, Runnable r, long when, MessageCompare compare, boolean removeMatches)2662     private boolean stackHasMessages(Handler h, int what, Object object, Runnable r, long when,
2663             MessageCompare compare, boolean removeMatches) {
2664         boolean found = false;
2665         StackNode top = (StackNode) sState.getVolatile(this);
2666         StateNode bottom = getStateNode(top);
2667 
2668         /*
2669          * If the top node is a state node, there are no reachable messages.
2670          * If it's anything other than Active, we can quit as we know that next() is not
2671          * consuming items.
2672          * If the top node is Active then we know that next() is currently consuming items.
2673          * In that case we should wait next() has drained the stack.
2674          */
2675         if (top == bottom) {
2676             if (bottom != sStackStateActive) {
2677                 return false;
2678             }
2679             waitForDrainCompleted();
2680             return false;
2681         }
2682 
2683         /*
2684          * We have messages that we may tombstone. Walk the stack until we hit the bottom or we
2685          * hit a null pointer.
2686          * If we hit the bottom, we are done.
2687          * If we hit a null pointer, then the stack is being consumed by next() and we must cycle
2688          * until the stack has been drained.
2689          */
2690         MessageNode p = (MessageNode) top;
2691 
2692         while (true) {
2693             if (compare.compareMessage(p, h, what, object, r, when)) {
2694                 found = true;
2695                 if (DEBUG) {
2696                     Log.d(TAG_C, "stackHasMessages node matches");
2697                 }
2698                 if (removeMatches) {
2699                     if (p.removeFromStack()) {
2700                         p.mMessage.recycleUnchecked();
2701                         if (mMessageCounts.incrementCancelled()) {
2702                             nativeWake(mPtr);
2703                         }
2704                     }
2705                 } else {
2706                     return true;
2707                 }
2708             }
2709 
2710             StackNode n = p.mNext;
2711             if (n == null) {
2712                 /* Next() is walking the stack, we must re-sample */
2713                 if (DEBUG) {
2714                     Log.d(TAG_C, "stackHasMessages next() is walking the stack, we must re-sample");
2715                 }
2716                 waitForDrainCompleted();
2717                 break;
2718             }
2719             if (!n.isMessageNode()) {
2720                 /* We reached the end of the stack */
2721                 return found;
2722             }
2723             p = (MessageNode) n;
2724         }
2725 
2726         return found;
2727     }
2728 
priorityQueueHasMessage(ConcurrentSkipListSet<MessageNode> queue, Handler h, int what, Object object, Runnable r, long when, MessageCompare compare, boolean removeMatches)2729     private boolean priorityQueueHasMessage(ConcurrentSkipListSet<MessageNode> queue, Handler h,
2730             int what, Object object, Runnable r, long when, MessageCompare compare,
2731             boolean removeMatches) {
2732         Iterator<MessageNode> iterator = queue.iterator();
2733         boolean found = false;
2734 
2735         while (iterator.hasNext()) {
2736             MessageNode msg = iterator.next();
2737 
2738             if (compare.compareMessage(msg, h, what, object, r, when)) {
2739                 if (removeMatches) {
2740                     found = true;
2741                     if (queue.remove(msg)) {
2742                         msg.mMessage.recycleUnchecked();
2743                     }
2744                 } else {
2745                     return true;
2746                 }
2747             }
2748         }
2749         return found;
2750     }
2751 
findOrRemoveMessages(Handler h, int what, Object object, Runnable r, long when, MessageCompare compare, boolean removeMatches)2752     private boolean findOrRemoveMessages(Handler h, int what, Object object, Runnable r, long when,
2753             MessageCompare compare, boolean removeMatches) {
2754         boolean foundInStack, foundInQueue;
2755 
2756         foundInStack = stackHasMessages(h, what, object, r, when, compare, removeMatches);
2757         foundInQueue = priorityQueueHasMessage(mPriorityQueue, h, what, object, r, when, compare,
2758                 removeMatches);
2759         foundInQueue |= priorityQueueHasMessage(mAsyncPriorityQueue, h, what, object, r, when,
2760                 compare, removeMatches);
2761 
2762         return foundInStack || foundInQueue;
2763     }
2764 
2765 }
2766