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.TestApi;
22 import android.compat.annotation.UnsupportedAppUsage;
23 import android.util.Log;
24 import android.util.Printer;
25 import android.util.SparseArray;
26 import android.util.proto.ProtoOutputStream;
27 
28 import java.io.FileDescriptor;
29 import java.lang.annotation.Retention;
30 import java.lang.annotation.RetentionPolicy;
31 import java.util.ArrayList;
32 
33 /**
34  * Low-level class holding the list of messages to be dispatched by a
35  * {@link Looper}.  Messages are not added directly to a MessageQueue,
36  * but rather through {@link Handler} objects associated with the Looper.
37  *
38  * <p>You can retrieve the MessageQueue for the current thread with
39  * {@link Looper#myQueue() Looper.myQueue()}.
40  */
41 @android.ravenwood.annotation.RavenwoodKeepWholeClass
42 @android.ravenwood.annotation.RavenwoodNativeSubstitutionClass(
43         "com.android.platform.test.ravenwood.nativesubstitution.MessageQueue_host")
44 public final class MessageQueue {
45     private static final String TAG = "MessageQueue";
46     private static final boolean DEBUG = false;
47 
48     // True if the message queue can be quit.
49     @UnsupportedAppUsage
50     private final boolean mQuitAllowed;
51 
52     @UnsupportedAppUsage
53     @SuppressWarnings("unused")
54     private long mPtr; // used by native code
55 
56     @UnsupportedAppUsage
57     Message mMessages;
58     private Message mLast;
59     @UnsupportedAppUsage
60     private final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<IdleHandler>();
61     private SparseArray<FileDescriptorRecord> mFileDescriptorRecords;
62     private IdleHandler[] mPendingIdleHandlers;
63     private boolean mQuitting;
64 
65     // Indicates whether next() is blocked waiting in pollOnce() with a non-zero timeout.
66     private boolean mBlocked;
67 
68     // Tracks the number of async message. We use this in enqueueMessage() to avoid searching the
69     // queue for async messages when inserting a message at the tail.
70     private int mAsyncMessageCount;
71 
72     // The next barrier token.
73     // Barriers are indicated by messages with a null target whose arg1 field carries the token.
74     @UnsupportedAppUsage
75     private int mNextBarrierToken;
76 
nativeInit()77     private native static long nativeInit();
nativeDestroy(long ptr)78     private native static void nativeDestroy(long ptr);
79     @UnsupportedAppUsage
nativePollOnce(long ptr, int timeoutMillis)80     private native void nativePollOnce(long ptr, int timeoutMillis); /*non-static for callbacks*/
nativeWake(long ptr)81     private native static void nativeWake(long ptr);
nativeIsPolling(long ptr)82     private native static boolean nativeIsPolling(long ptr);
nativeSetFileDescriptorEvents(long ptr, int fd, int events)83     private native static void nativeSetFileDescriptorEvents(long ptr, int fd, int events);
84 
MessageQueue(boolean quitAllowed)85     MessageQueue(boolean quitAllowed) {
86         mQuitAllowed = quitAllowed;
87         mPtr = nativeInit();
88     }
89 
90     @Override
finalize()91     protected void finalize() throws Throwable {
92         try {
93             dispose();
94         } finally {
95             super.finalize();
96         }
97     }
98 
99     // Disposes of the underlying message queue.
100     // Must only be called on the looper thread or the finalizer.
dispose()101     private void dispose() {
102         if (mPtr != 0) {
103             nativeDestroy(mPtr);
104             mPtr = 0;
105         }
106     }
107 
108     /**
109      * Returns true if the looper has no pending messages which are due to be processed.
110      *
111      * <p>This method is safe to call from any thread.
112      *
113      * @return True if the looper is idle.
114      */
isIdle()115     public boolean isIdle() {
116         synchronized (this) {
117             final long now = SystemClock.uptimeMillis();
118             return mMessages == null || now < mMessages.when;
119         }
120     }
121 
122     /**
123      * Add a new {@link IdleHandler} to this message queue.  This may be
124      * removed automatically for you by returning false from
125      * {@link IdleHandler#queueIdle IdleHandler.queueIdle()} when it is
126      * invoked, or explicitly removing it with {@link #removeIdleHandler}.
127      *
128      * <p>This method is safe to call from any thread.
129      *
130      * @param handler The IdleHandler to be added.
131      */
addIdleHandler(@onNull IdleHandler handler)132     public void addIdleHandler(@NonNull IdleHandler handler) {
133         if (handler == null) {
134             throw new NullPointerException("Can't add a null IdleHandler");
135         }
136         synchronized (this) {
137             mIdleHandlers.add(handler);
138         }
139     }
140 
141     /**
142      * Remove an {@link IdleHandler} from the queue that was previously added
143      * with {@link #addIdleHandler}.  If the given object is not currently
144      * in the idle list, nothing is done.
145      *
146      * <p>This method is safe to call from any thread.
147      *
148      * @param handler The IdleHandler to be removed.
149      */
removeIdleHandler(@onNull IdleHandler handler)150     public void removeIdleHandler(@NonNull IdleHandler handler) {
151         synchronized (this) {
152             mIdleHandlers.remove(handler);
153         }
154     }
155 
156     /**
157      * Returns whether this looper's thread is currently polling for more work to do.
158      * This is a good signal that the loop is still alive rather than being stuck
159      * handling a callback.  Note that this method is intrinsically racy, since the
160      * state of the loop can change before you get the result back.
161      *
162      * <p>This method is safe to call from any thread.
163      *
164      * @return True if the looper is currently polling for events.
165      * @hide
166      */
isPolling()167     public boolean isPolling() {
168         synchronized (this) {
169             return isPollingLocked();
170         }
171     }
172 
isPollingLocked()173     private boolean isPollingLocked() {
174         // If the loop is quitting then it must not be idling.
175         // We can assume mPtr != 0 when mQuitting is false.
176         return !mQuitting && nativeIsPolling(mPtr);
177     }
178 
179     /**
180      * Adds a file descriptor listener to receive notification when file descriptor
181      * related events occur.
182      * <p>
183      * If the file descriptor has already been registered, the specified events
184      * and listener will replace any that were previously associated with it.
185      * It is not possible to set more than one listener per file descriptor.
186      * </p><p>
187      * It is important to always unregister the listener when the file descriptor
188      * is no longer of use.
189      * </p>
190      *
191      * @param fd The file descriptor for which a listener will be registered.
192      * @param events The set of events to receive: a combination of the
193      * {@link OnFileDescriptorEventListener#EVENT_INPUT},
194      * {@link OnFileDescriptorEventListener#EVENT_OUTPUT}, and
195      * {@link OnFileDescriptorEventListener#EVENT_ERROR} event masks.  If the requested
196      * set of events is zero, then the listener is unregistered.
197      * @param listener The listener to invoke when file descriptor events occur.
198      *
199      * @see OnFileDescriptorEventListener
200      * @see #removeOnFileDescriptorEventListener
201      */
202     @android.ravenwood.annotation.RavenwoodThrow(blockedBy = android.os.ParcelFileDescriptor.class)
addOnFileDescriptorEventListener(@onNull FileDescriptor fd, @OnFileDescriptorEventListener.Events int events, @NonNull OnFileDescriptorEventListener listener)203     public void addOnFileDescriptorEventListener(@NonNull FileDescriptor fd,
204             @OnFileDescriptorEventListener.Events int events,
205             @NonNull OnFileDescriptorEventListener listener) {
206         if (fd == null) {
207             throw new IllegalArgumentException("fd must not be null");
208         }
209         if (listener == null) {
210             throw new IllegalArgumentException("listener must not be null");
211         }
212 
213         synchronized (this) {
214             updateOnFileDescriptorEventListenerLocked(fd, events, listener);
215         }
216     }
217 
218     /**
219      * Removes a file descriptor listener.
220      * <p>
221      * This method does nothing if no listener has been registered for the
222      * specified file descriptor.
223      * </p>
224      *
225      * @param fd The file descriptor whose listener will be unregistered.
226      *
227      * @see OnFileDescriptorEventListener
228      * @see #addOnFileDescriptorEventListener
229      */
230     @android.ravenwood.annotation.RavenwoodThrow(blockedBy = android.os.ParcelFileDescriptor.class)
removeOnFileDescriptorEventListener(@onNull FileDescriptor fd)231     public void removeOnFileDescriptorEventListener(@NonNull FileDescriptor fd) {
232         if (fd == null) {
233             throw new IllegalArgumentException("fd must not be null");
234         }
235 
236         synchronized (this) {
237             updateOnFileDescriptorEventListenerLocked(fd, 0, null);
238         }
239     }
240 
241     @android.ravenwood.annotation.RavenwoodThrow(blockedBy = android.os.ParcelFileDescriptor.class)
updateOnFileDescriptorEventListenerLocked(FileDescriptor fd, int events, OnFileDescriptorEventListener listener)242     private void updateOnFileDescriptorEventListenerLocked(FileDescriptor fd, int events,
243             OnFileDescriptorEventListener listener) {
244         final int fdNum = fd.getInt$();
245 
246         int index = -1;
247         FileDescriptorRecord record = null;
248         if (mFileDescriptorRecords != null) {
249             index = mFileDescriptorRecords.indexOfKey(fdNum);
250             if (index >= 0) {
251                 record = mFileDescriptorRecords.valueAt(index);
252                 if (record != null && record.mEvents == events) {
253                     return;
254                 }
255             }
256         }
257 
258         if (events != 0) {
259             events |= OnFileDescriptorEventListener.EVENT_ERROR;
260             if (record == null) {
261                 if (mFileDescriptorRecords == null) {
262                     mFileDescriptorRecords = new SparseArray<FileDescriptorRecord>();
263                 }
264                 record = new FileDescriptorRecord(fd, events, listener);
265                 mFileDescriptorRecords.put(fdNum, record);
266             } else {
267                 record.mListener = listener;
268                 record.mEvents = events;
269                 record.mSeq += 1;
270             }
271             nativeSetFileDescriptorEvents(mPtr, fdNum, events);
272         } else if (record != null) {
273             record.mEvents = 0;
274             mFileDescriptorRecords.removeAt(index);
275             nativeSetFileDescriptorEvents(mPtr, fdNum, 0);
276         }
277     }
278 
279     // Called from native code.
280     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
dispatchEvents(int fd, int events)281     private int dispatchEvents(int fd, int events) {
282         // Get the file descriptor record and any state that might change.
283         final FileDescriptorRecord record;
284         final int oldWatchedEvents;
285         final OnFileDescriptorEventListener listener;
286         final int seq;
287         synchronized (this) {
288             record = mFileDescriptorRecords.get(fd);
289             if (record == null) {
290                 return 0; // spurious, no listener registered
291             }
292 
293             oldWatchedEvents = record.mEvents;
294             events &= oldWatchedEvents; // filter events based on current watched set
295             if (events == 0) {
296                 return oldWatchedEvents; // spurious, watched events changed
297             }
298 
299             listener = record.mListener;
300             seq = record.mSeq;
301         }
302 
303         // Invoke the listener outside of the lock.
304         int newWatchedEvents = listener.onFileDescriptorEvents(
305                 record.mDescriptor, events);
306         if (newWatchedEvents != 0) {
307             newWatchedEvents |= OnFileDescriptorEventListener.EVENT_ERROR;
308         }
309 
310         // Update the file descriptor record if the listener changed the set of
311         // events to watch and the listener itself hasn't been updated since.
312         if (newWatchedEvents != oldWatchedEvents) {
313             synchronized (this) {
314                 int index = mFileDescriptorRecords.indexOfKey(fd);
315                 if (index >= 0 && mFileDescriptorRecords.valueAt(index) == record
316                         && record.mSeq == seq) {
317                     record.mEvents = newWatchedEvents;
318                     if (newWatchedEvents == 0) {
319                         mFileDescriptorRecords.removeAt(index);
320                     }
321                 }
322             }
323         }
324 
325         // Return the new set of events to watch for native code to take care of.
326         return newWatchedEvents;
327     }
328 
329     @UnsupportedAppUsage
next()330     Message next() {
331         // Return here if the message loop has already quit and been disposed.
332         // This can happen if the application tries to restart a looper after quit
333         // which is not supported.
334         final long ptr = mPtr;
335         if (ptr == 0) {
336             return null;
337         }
338 
339         int pendingIdleHandlerCount = -1; // -1 only during first iteration
340         int nextPollTimeoutMillis = 0;
341         for (;;) {
342             if (nextPollTimeoutMillis != 0) {
343                 Binder.flushPendingCommands();
344             }
345 
346             nativePollOnce(ptr, nextPollTimeoutMillis);
347 
348             synchronized (this) {
349                 // Try to retrieve the next message.  Return if found.
350                 final long now = SystemClock.uptimeMillis();
351                 Message prevMsg = null;
352                 Message msg = mMessages;
353                 if (msg != null && msg.target == null) {
354                     // Stalled by a barrier.  Find the next asynchronous message in the queue.
355                     do {
356                         prevMsg = msg;
357                         msg = msg.next;
358                     } while (msg != null && !msg.isAsynchronous());
359                 }
360                 if (msg != null) {
361                     if (now < msg.when) {
362                         // Next message is not ready.  Set a timeout to wake up when it is ready.
363                         nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
364                     } else {
365                         // Got a message.
366                         mBlocked = false;
367                         if (prevMsg != null) {
368                             prevMsg.next = msg.next;
369                             if (prevMsg.next == null) {
370                                 mLast = prevMsg;
371                             }
372                         } else {
373                             mMessages = msg.next;
374                             if (msg.next == null) {
375                                 mLast = null;
376                             }
377                         }
378                         msg.next = null;
379                         if (DEBUG) Log.v(TAG, "Returning message: " + msg);
380                         msg.markInUse();
381                         if (msg.isAsynchronous()) {
382                             mAsyncMessageCount--;
383                         }
384                         return msg;
385                     }
386                 } else {
387                     // No more messages.
388                     nextPollTimeoutMillis = -1;
389                 }
390 
391                 // Process the quit message now that all pending messages have been handled.
392                 if (mQuitting) {
393                     dispose();
394                     return null;
395                 }
396 
397                 // If first time idle, then get the number of idlers to run.
398                 // Idle handles only run if the queue is empty or if the first message
399                 // in the queue (possibly a barrier) is due to be handled in the future.
400                 if (pendingIdleHandlerCount < 0
401                         && (mMessages == null || now < mMessages.when)) {
402                     pendingIdleHandlerCount = mIdleHandlers.size();
403                 }
404                 if (pendingIdleHandlerCount <= 0) {
405                     // No idle handlers to run.  Loop and wait some more.
406                     mBlocked = true;
407                     continue;
408                 }
409 
410                 if (mPendingIdleHandlers == null) {
411                     mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
412                 }
413                 mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
414             }
415 
416             // Run the idle handlers.
417             // We only ever reach this code block during the first iteration.
418             for (int i = 0; i < pendingIdleHandlerCount; i++) {
419                 final IdleHandler idler = mPendingIdleHandlers[i];
420                 mPendingIdleHandlers[i] = null; // release the reference to the handler
421 
422                 boolean keep = false;
423                 try {
424                     keep = idler.queueIdle();
425                 } catch (Throwable t) {
426                     Log.wtf(TAG, "IdleHandler threw exception", t);
427                 }
428 
429                 if (!keep) {
430                     synchronized (this) {
431                         mIdleHandlers.remove(idler);
432                     }
433                 }
434             }
435 
436             // Reset the idle handler count to 0 so we do not run them again.
437             pendingIdleHandlerCount = 0;
438 
439             // While calling an idle handler, a new message could have been delivered
440             // so go back and look again for a pending message without waiting.
441             nextPollTimeoutMillis = 0;
442         }
443     }
444 
quit(boolean safe)445     void quit(boolean safe) {
446         if (!mQuitAllowed) {
447             throw new IllegalStateException("Main thread not allowed to quit.");
448         }
449 
450         synchronized (this) {
451             if (mQuitting) {
452                 return;
453             }
454             mQuitting = true;
455 
456             if (safe) {
457                 removeAllFutureMessagesLocked();
458             } else {
459                 removeAllMessagesLocked();
460             }
461 
462             // We can assume mPtr != 0 because mQuitting was previously false.
463             nativeWake(mPtr);
464         }
465     }
466 
467     /**
468      * Posts a synchronization barrier to the Looper's message queue.
469      *
470      * Message processing occurs as usual until the message queue encounters the
471      * synchronization barrier that has been posted.  When the barrier is encountered,
472      * later synchronous messages in the queue are stalled (prevented from being executed)
473      * until the barrier is released by calling {@link #removeSyncBarrier} and specifying
474      * the token that identifies the synchronization barrier.
475      *
476      * This method is used to immediately postpone execution of all subsequently posted
477      * synchronous messages until a condition is met that releases the barrier.
478      * Asynchronous messages (see {@link Message#isAsynchronous} are exempt from the barrier
479      * and continue to be processed as usual.
480      *
481      * This call must be always matched by a call to {@link #removeSyncBarrier} with
482      * the same token to ensure that the message queue resumes normal operation.
483      * Otherwise the application will probably hang!
484      *
485      * @return A token that uniquely identifies the barrier.  This token must be
486      * passed to {@link #removeSyncBarrier} to release the barrier.
487      *
488      * @hide
489      */
490     @UnsupportedAppUsage
491     @TestApi
postSyncBarrier()492     public int postSyncBarrier() {
493         return postSyncBarrier(SystemClock.uptimeMillis());
494     }
495 
postSyncBarrier(long when)496     private int postSyncBarrier(long when) {
497         // Enqueue a new sync barrier token.
498         // We don't need to wake the queue because the purpose of a barrier is to stall it.
499         synchronized (this) {
500             final int token = mNextBarrierToken++;
501             final Message msg = Message.obtain();
502             msg.markInUse();
503             msg.when = when;
504             msg.arg1 = token;
505 
506             if (Flags.messageQueueTailTracking() && mLast != null && mLast.when <= when) {
507                 /* Message goes to tail of list */
508                 mLast.next = msg;
509                 mLast = msg;
510                 msg.next = null;
511                 return token;
512             }
513 
514             Message prev = null;
515             Message p = mMessages;
516             if (when != 0) {
517                 while (p != null && p.when <= when) {
518                     prev = p;
519                     p = p.next;
520                 }
521             }
522 
523             if (p == null) {
524                 /* We reached the tail of the list, or list is empty. */
525                 mLast = msg;
526             }
527 
528             if (prev != null) { // invariant: p == prev.next
529                 msg.next = p;
530                 prev.next = msg;
531             } else {
532                 msg.next = p;
533                 mMessages = msg;
534             }
535             return token;
536         }
537     }
538 
539     /**
540      * Removes a synchronization barrier.
541      *
542      * @param token The synchronization barrier token that was returned by
543      * {@link #postSyncBarrier}.
544      *
545      * @throws IllegalStateException if the barrier was not found.
546      *
547      * @hide
548      */
549     @UnsupportedAppUsage
550     @TestApi
removeSyncBarrier(int token)551     public void removeSyncBarrier(int token) {
552         // Remove a sync barrier token from the queue.
553         // If the queue is no longer stalled by a barrier then wake it.
554         synchronized (this) {
555             Message prev = null;
556             Message p = mMessages;
557             while (p != null && (p.target != null || p.arg1 != token)) {
558                 prev = p;
559                 p = p.next;
560             }
561             if (p == null) {
562                 throw new IllegalStateException("The specified message queue synchronization "
563                         + " barrier token has not been posted or has already been removed.");
564             }
565             final boolean needWake;
566             if (prev != null) {
567                 prev.next = p.next;
568                 if (prev.next == null) {
569                     mLast = prev;
570                 }
571                 needWake = false;
572             } else {
573                 mMessages = p.next;
574                 if (mMessages == null) {
575                     mLast = null;
576                 }
577                 needWake = mMessages == null || mMessages.target != null;
578             }
579             p.recycleUnchecked();
580 
581             // If the loop is quitting then it is already awake.
582             // We can assume mPtr != 0 when mQuitting is false.
583             if (needWake && !mQuitting) {
584                 nativeWake(mPtr);
585             }
586         }
587     }
588 
enqueueMessage(Message msg, long when)589     boolean enqueueMessage(Message msg, long when) {
590         if (msg.target == null) {
591             throw new IllegalArgumentException("Message must have a target.");
592         }
593 
594         synchronized (this) {
595             if (msg.isInUse()) {
596                 throw new IllegalStateException(msg + " This message is already in use.");
597             }
598 
599             if (mQuitting) {
600                 IllegalStateException e = new IllegalStateException(
601                         msg.target + " sending message to a Handler on a dead thread");
602                 Log.w(TAG, e.getMessage(), e);
603                 msg.recycle();
604                 return false;
605             }
606 
607             msg.markInUse();
608             msg.when = when;
609             Message p = mMessages;
610             boolean needWake;
611             if (p == null || when == 0 || when < p.when) {
612                 // New head, wake up the event queue if blocked.
613                 msg.next = p;
614                 mMessages = msg;
615                 needWake = mBlocked;
616                 if (p == null) {
617                     mLast = mMessages;
618                 }
619             } else {
620                 // Message is to be inserted at tail or middle of queue. Usually we don't have to
621                 // wake up the event queue unless there is a barrier at the head of the queue and
622                 // the message is the earliest asynchronous message in the queue.
623                 needWake = mBlocked && p.target == null && msg.isAsynchronous();
624 
625                 // For readability, we split this portion of the function into two blocks based on
626                 // whether tail tracking is enabled. This has a minor implication for the case
627                 // where tail tracking is disabled. See the comment below.
628                 if (Flags.messageQueueTailTracking()) {
629                     if (when >= mLast.when) {
630                         needWake = needWake && mAsyncMessageCount == 0;
631                         msg.next = null;
632                         mLast.next = msg;
633                         mLast = msg;
634                     } else {
635                         // Inserted within the middle of the queue.
636                         Message prev;
637                         for (;;) {
638                             prev = p;
639                             p = p.next;
640                             if (p == null || when < p.when) {
641                                 break;
642                             }
643                             if (needWake && p.isAsynchronous()) {
644                                 needWake = false;
645                             }
646                         }
647                         if (p == null) {
648                             /* Inserting at tail of queue */
649                             mLast = msg;
650                         }
651                         msg.next = p; // invariant: p == prev.next
652                         prev.next = msg;
653                     }
654                 } else {
655                     Message prev;
656                     for (;;) {
657                         prev = p;
658                         p = p.next;
659                         if (p == null || when < p.when) {
660                             break;
661                         }
662                         if (needWake && p.isAsynchronous()) {
663                             needWake = false;
664                         }
665                     }
666                     msg.next = p; // invariant: p == prev.next
667                     prev.next = msg;
668 
669                     /*
670                      * If this block is executing then we have a build without tail tracking -
671                      * specifically: Flags.messageQueueTailTracking() == false. This is determined
672                      * at build time so the flag won't change on us during runtime.
673                      *
674                      * Since we don't want to pepper the code with extra checks, we only check
675                      * for tail tracking when we might use mLast. Otherwise, we continue to update
676                      * mLast as the tail of the list.
677                      *
678                      * In this case however we are not maintaining mLast correctly. Since we never
679                      * use it, this is fine. However, we run the risk of leaking a reference.
680                      * So set mLast to null in this case to avoid any Message leaks. The other
681                      * sites will never use the value so we are safe against null pointer derefs.
682                      */
683                     mLast = null;
684                 }
685             }
686 
687             if (msg.isAsynchronous()) {
688                 mAsyncMessageCount++;
689             }
690 
691             // We can assume mPtr != 0 because mQuitting is false.
692             if (needWake) {
693                 nativeWake(mPtr);
694             }
695         }
696         return true;
697     }
698 
hasMessages(Handler h, int what, Object object)699     boolean hasMessages(Handler h, int what, Object object) {
700         if (h == null) {
701             return false;
702         }
703 
704         synchronized (this) {
705             Message p = mMessages;
706             while (p != null) {
707                 if (p.target == h && p.what == what && (object == null || p.obj == object)) {
708                     return true;
709                 }
710                 p = p.next;
711             }
712             return false;
713         }
714     }
715 
hasEqualMessages(Handler h, int what, Object object)716     boolean hasEqualMessages(Handler h, int what, Object object) {
717         if (h == null) {
718             return false;
719         }
720 
721         synchronized (this) {
722             Message p = mMessages;
723             while (p != null) {
724                 if (p.target == h && p.what == what && (object == null || object.equals(p.obj))) {
725                     return true;
726                 }
727                 p = p.next;
728             }
729             return false;
730         }
731     }
732 
733     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
hasMessages(Handler h, Runnable r, Object object)734     boolean hasMessages(Handler h, Runnable r, Object object) {
735         if (h == null) {
736             return false;
737         }
738 
739         synchronized (this) {
740             Message p = mMessages;
741             while (p != null) {
742                 if (p.target == h && p.callback == r && (object == null || p.obj == object)) {
743                     return true;
744                 }
745                 p = p.next;
746             }
747             return false;
748         }
749     }
750 
hasMessages(Handler h)751     boolean hasMessages(Handler h) {
752         if (h == null) {
753             return false;
754         }
755 
756         synchronized (this) {
757             Message p = mMessages;
758             while (p != null) {
759                 if (p.target == h) {
760                     return true;
761                 }
762                 p = p.next;
763             }
764             return false;
765         }
766     }
767 
removeMessages(Handler h, int what, Object object)768     void removeMessages(Handler h, int what, Object object) {
769         if (h == null) {
770             return;
771         }
772 
773         synchronized (this) {
774             Message p = mMessages;
775 
776             // Remove all messages at front.
777             while (p != null && p.target == h && p.what == what
778                    && (object == null || p.obj == object)) {
779                 Message n = p.next;
780                 mMessages = n;
781                 if (p.isAsynchronous()) {
782                     mAsyncMessageCount--;
783                 }
784                 p.recycleUnchecked();
785                 p = n;
786             }
787 
788             if (p == null) {
789                 mLast = mMessages;
790             }
791 
792             // Remove all messages after front.
793             while (p != null) {
794                 Message n = p.next;
795                 if (n != null) {
796                     if (n.target == h && n.what == what
797                         && (object == null || n.obj == object)) {
798                         Message nn = n.next;
799                         if (n.isAsynchronous()) {
800                             mAsyncMessageCount--;
801                         }
802                         n.recycleUnchecked();
803                         p.next = nn;
804                         if (p.next == null) {
805                             mLast = p;
806                         }
807                         continue;
808                     }
809                 }
810                 p = n;
811             }
812         }
813     }
814 
removeEqualMessages(Handler h, int what, Object object)815     void removeEqualMessages(Handler h, int what, Object object) {
816         if (h == null) {
817             return;
818         }
819 
820         synchronized (this) {
821             Message p = mMessages;
822 
823             // Remove all messages at front.
824             while (p != null && p.target == h && p.what == what
825                    && (object == null || object.equals(p.obj))) {
826                 Message n = p.next;
827                 mMessages = n;
828                 if (p.isAsynchronous()) {
829                     mAsyncMessageCount--;
830                 }
831                 p.recycleUnchecked();
832                 p = n;
833             }
834 
835             if (p == null) {
836                 mLast = mMessages;
837             }
838 
839             // Remove all messages after front.
840             while (p != null) {
841                 Message n = p.next;
842                 if (n != null) {
843                     if (n.target == h && n.what == what
844                         && (object == null || object.equals(n.obj))) {
845                         Message nn = n.next;
846                         if (n.isAsynchronous()) {
847                             mAsyncMessageCount--;
848                         }
849                         n.recycleUnchecked();
850                         p.next = nn;
851                         if (p.next == null) {
852                             mLast = p;
853                         }
854                         continue;
855                     }
856                 }
857                 p = n;
858             }
859         }
860     }
861 
removeMessages(Handler h, Runnable r, Object object)862     void removeMessages(Handler h, Runnable r, Object object) {
863         if (h == null || r == null) {
864             return;
865         }
866 
867         synchronized (this) {
868             Message p = mMessages;
869 
870             // Remove all messages at front.
871             while (p != null && p.target == h && p.callback == r
872                    && (object == null || p.obj == object)) {
873                 Message n = p.next;
874                 mMessages = n;
875                 if (p.isAsynchronous()) {
876                     mAsyncMessageCount--;
877                 }
878                 p.recycleUnchecked();
879                 p = n;
880             }
881 
882             if (p == null) {
883                 mLast = mMessages;
884             }
885 
886             // Remove all messages after front.
887             while (p != null) {
888                 Message n = p.next;
889                 if (n != null) {
890                     if (n.target == h && n.callback == r
891                         && (object == null || n.obj == object)) {
892                         Message nn = n.next;
893                         if (n.isAsynchronous()) {
894                             mAsyncMessageCount--;
895                         }
896                         n.recycleUnchecked();
897                         p.next = nn;
898                         if (p.next == null) {
899                             mLast = p;
900                         }
901                         continue;
902                     }
903                 }
904                 p = n;
905             }
906         }
907     }
908 
removeEqualMessages(Handler h, Runnable r, Object object)909     void removeEqualMessages(Handler h, Runnable r, Object object) {
910         if (h == null || r == null) {
911             return;
912         }
913 
914         synchronized (this) {
915             Message p = mMessages;
916 
917             // Remove all messages at front.
918             while (p != null && p.target == h && p.callback == r
919                    && (object == null || object.equals(p.obj))) {
920                 Message n = p.next;
921                 mMessages = n;
922                 if (p.isAsynchronous()) {
923                     mAsyncMessageCount--;
924                 }
925                 p.recycleUnchecked();
926                 p = n;
927             }
928 
929             if (p == null) {
930                 mLast = mMessages;
931             }
932 
933             // Remove all messages after front.
934             while (p != null) {
935                 Message n = p.next;
936                 if (n != null) {
937                     if (n.target == h && n.callback == r
938                         && (object == null || object.equals(n.obj))) {
939                         Message nn = n.next;
940                         if (n.isAsynchronous()) {
941                             mAsyncMessageCount--;
942                         }
943                         n.recycleUnchecked();
944                         p.next = nn;
945                         if (p.next == null) {
946                             mLast = p;
947                         }
948                         continue;
949                     }
950                 }
951                 p = n;
952             }
953         }
954     }
955 
956 
removeCallbacksAndMessages(Handler h, Object object)957     void removeCallbacksAndMessages(Handler h, Object object) {
958         if (h == null) {
959             return;
960         }
961 
962         synchronized (this) {
963             Message p = mMessages;
964 
965             // Remove all messages at front.
966             while (p != null && p.target == h
967                     && (object == null || p.obj == object)) {
968                 Message n = p.next;
969                 mMessages = n;
970                 if (p.isAsynchronous()) {
971                     mAsyncMessageCount--;
972                 }
973                 p.recycleUnchecked();
974                 p = n;
975             }
976 
977             if (p == null) {
978                 mLast = mMessages;
979             }
980 
981             // Remove all messages after front.
982             while (p != null) {
983                 Message n = p.next;
984                 if (n != null) {
985                     if (n.target == h && (object == null || n.obj == object)) {
986                         Message nn = n.next;
987                         if (n.isAsynchronous()) {
988                             mAsyncMessageCount--;
989                         }
990                         n.recycleUnchecked();
991                         p.next = nn;
992                         if (p.next == null) {
993                             mLast = p;
994                         }
995                         continue;
996                     }
997                 }
998                 p = n;
999             }
1000         }
1001     }
1002 
removeCallbacksAndEqualMessages(Handler h, Object object)1003     void removeCallbacksAndEqualMessages(Handler h, Object object) {
1004         if (h == null) {
1005             return;
1006         }
1007 
1008         synchronized (this) {
1009             Message p = mMessages;
1010 
1011             // Remove all messages at front.
1012             while (p != null && p.target == h
1013                     && (object == null || object.equals(p.obj))) {
1014                 Message n = p.next;
1015                 mMessages = n;
1016                 if (p.isAsynchronous()) {
1017                     mAsyncMessageCount--;
1018                 }
1019                 p.recycleUnchecked();
1020                 p = n;
1021             }
1022 
1023             if (p == null) {
1024                 mLast = mMessages;
1025             }
1026 
1027             // Remove all messages after front.
1028             while (p != null) {
1029                 Message n = p.next;
1030                 if (n != null) {
1031                     if (n.target == h && (object == null || object.equals(n.obj))) {
1032                         Message nn = n.next;
1033                         if (n.isAsynchronous()) {
1034                             mAsyncMessageCount--;
1035                         }
1036                         n.recycleUnchecked();
1037                         p.next = nn;
1038                         if (p.next == null) {
1039                             mLast = p;
1040                         }
1041                         continue;
1042                     }
1043                 }
1044                 p = n;
1045             }
1046         }
1047     }
1048 
removeAllMessagesLocked()1049     private void removeAllMessagesLocked() {
1050         Message p = mMessages;
1051         while (p != null) {
1052             Message n = p.next;
1053             p.recycleUnchecked();
1054             p = n;
1055         }
1056         mMessages = null;
1057         mLast = null;
1058         mAsyncMessageCount = 0;
1059     }
1060 
removeAllFutureMessagesLocked()1061     private void removeAllFutureMessagesLocked() {
1062         final long now = SystemClock.uptimeMillis();
1063         Message p = mMessages;
1064         if (p != null) {
1065             if (p.when > now) {
1066                 removeAllMessagesLocked();
1067             } else {
1068                 Message n;
1069                 for (;;) {
1070                     n = p.next;
1071                     if (n == null) {
1072                         return;
1073                     }
1074                     if (n.when > now) {
1075                         break;
1076                     }
1077                     p = n;
1078                 }
1079                 p.next = null;
1080                 mLast = p;
1081 
1082                 do {
1083                     p = n;
1084                     n = p.next;
1085                     if (p.isAsynchronous()) {
1086                         mAsyncMessageCount--;
1087                     }
1088                     p.recycleUnchecked();
1089                 } while (n != null);
1090             }
1091         }
1092     }
1093 
dump(Printer pw, String prefix, Handler h)1094     void dump(Printer pw, String prefix, Handler h) {
1095         synchronized (this) {
1096             long now = SystemClock.uptimeMillis();
1097             int n = 0;
1098             for (Message msg = mMessages; msg != null; msg = msg.next) {
1099                 if (h == null || h == msg.target) {
1100                     pw.println(prefix + "Message " + n + ": " + msg.toString(now));
1101                 }
1102                 n++;
1103             }
1104             pw.println(prefix + "(Total messages: " + n + ", polling=" + isPollingLocked()
1105                     + ", quitting=" + mQuitting + ")");
1106         }
1107     }
1108 
dumpDebug(ProtoOutputStream proto, long fieldId)1109     void dumpDebug(ProtoOutputStream proto, long fieldId) {
1110         final long messageQueueToken = proto.start(fieldId);
1111         synchronized (this) {
1112             for (Message msg = mMessages; msg != null; msg = msg.next) {
1113                 msg.dumpDebug(proto, MessageQueueProto.MESSAGES);
1114             }
1115             proto.write(MessageQueueProto.IS_POLLING_LOCKED, isPollingLocked());
1116             proto.write(MessageQueueProto.IS_QUITTING, mQuitting);
1117         }
1118         proto.end(messageQueueToken);
1119     }
1120 
1121     /**
1122      * Callback interface for discovering when a thread is going to block
1123      * waiting for more messages.
1124      */
1125     public static interface IdleHandler {
1126         /**
1127          * Called when the message queue has run out of messages and will now
1128          * wait for more.  Return true to keep your idle handler active, false
1129          * to have it removed.  This may be called if there are still messages
1130          * pending in the queue, but they are all scheduled to be dispatched
1131          * after the current time.
1132          */
queueIdle()1133         boolean queueIdle();
1134     }
1135 
1136     /**
1137      * A listener which is invoked when file descriptor related events occur.
1138      */
1139     public interface OnFileDescriptorEventListener {
1140         /**
1141          * File descriptor event: Indicates that the file descriptor is ready for input
1142          * operations, such as reading.
1143          * <p>
1144          * The listener should read all available data from the file descriptor
1145          * then return <code>true</code> to keep the listener active or <code>false</code>
1146          * to remove the listener.
1147          * </p><p>
1148          * In the case of a socket, this event may be generated to indicate
1149          * that there is at least one incoming connection that the listener
1150          * should accept.
1151          * </p><p>
1152          * This event will only be generated if the {@link #EVENT_INPUT} event mask was
1153          * specified when the listener was added.
1154          * </p>
1155          */
1156         public static final int EVENT_INPUT = 1 << 0;
1157 
1158         /**
1159          * File descriptor event: Indicates that the file descriptor is ready for output
1160          * operations, such as writing.
1161          * <p>
1162          * The listener should write as much data as it needs.  If it could not
1163          * write everything at once, then it should return <code>true</code> to
1164          * keep the listener active.  Otherwise, it should return <code>false</code>
1165          * to remove the listener then re-register it later when it needs to write
1166          * something else.
1167          * </p><p>
1168          * This event will only be generated if the {@link #EVENT_OUTPUT} event mask was
1169          * specified when the listener was added.
1170          * </p>
1171          */
1172         public static final int EVENT_OUTPUT = 1 << 1;
1173 
1174         /**
1175          * File descriptor event: Indicates that the file descriptor encountered a
1176          * fatal error.
1177          * <p>
1178          * File descriptor errors can occur for various reasons.  One common error
1179          * is when the remote peer of a socket or pipe closes its end of the connection.
1180          * </p><p>
1181          * This event may be generated at any time regardless of whether the
1182          * {@link #EVENT_ERROR} event mask was specified when the listener was added.
1183          * </p>
1184          */
1185         public static final int EVENT_ERROR = 1 << 2;
1186 
1187         /** @hide */
1188         @Retention(RetentionPolicy.SOURCE)
1189         @IntDef(flag = true, prefix = { "EVENT_" }, value = {
1190                 EVENT_INPUT,
1191                 EVENT_OUTPUT,
1192                 EVENT_ERROR
1193         })
1194         public @interface Events {}
1195 
1196         /**
1197          * Called when a file descriptor receives events.
1198          *
1199          * @param fd The file descriptor.
1200          * @param events The set of events that occurred: a combination of the
1201          * {@link #EVENT_INPUT}, {@link #EVENT_OUTPUT}, and {@link #EVENT_ERROR} event masks.
1202          * @return The new set of events to watch, or 0 to unregister the listener.
1203          *
1204          * @see #EVENT_INPUT
1205          * @see #EVENT_OUTPUT
1206          * @see #EVENT_ERROR
1207          */
onFileDescriptorEvents(@onNull FileDescriptor fd, @Events int events)1208         @Events int onFileDescriptorEvents(@NonNull FileDescriptor fd, @Events int events);
1209     }
1210 
1211     private static final class FileDescriptorRecord {
1212         public final FileDescriptor mDescriptor;
1213         public int mEvents;
1214         public OnFileDescriptorEventListener mListener;
1215         public int mSeq;
1216 
FileDescriptorRecord(FileDescriptor descriptor, int events, OnFileDescriptorEventListener listener)1217         public FileDescriptorRecord(FileDescriptor descriptor,
1218                 int events, OnFileDescriptorEventListener listener) {
1219             mDescriptor = descriptor;
1220             mEvents = events;
1221             mListener = listener;
1222         }
1223     }
1224 }
1225