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