• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
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 
554         synchronized (this) {
555             if (msg.isInUse()) {
556                 throw new IllegalStateException(msg + " This message is already in use.");
557             }
558 
559             if (mQuitting) {
560                 IllegalStateException e = new IllegalStateException(
561                         msg.target + " sending message to a Handler on a dead thread");
562                 Log.w(TAG, e.getMessage(), e);
563                 msg.recycle();
564                 return false;
565             }
566 
567             msg.markInUse();
568             msg.when = when;
569             Message p = mMessages;
570             boolean needWake;
571             if (p == null || when == 0 || when < p.when) {
572                 // New head, wake up the event queue if blocked.
573                 msg.next = p;
574                 mMessages = msg;
575                 needWake = mBlocked;
576             } else {
577                 // Inserted within the middle of the queue.  Usually we don't have to wake
578                 // up the event queue unless there is a barrier at the head of the queue
579                 // and the message is the earliest asynchronous message in the queue.
580                 needWake = mBlocked && p.target == null && msg.isAsynchronous();
581                 Message prev;
582                 for (;;) {
583                     prev = p;
584                     p = p.next;
585                     if (p == null || when < p.when) {
586                         break;
587                     }
588                     if (needWake && p.isAsynchronous()) {
589                         needWake = false;
590                     }
591                 }
592                 msg.next = p; // invariant: p == prev.next
593                 prev.next = msg;
594             }
595 
596             // We can assume mPtr != 0 because mQuitting is false.
597             if (needWake) {
598                 nativeWake(mPtr);
599             }
600         }
601         return true;
602     }
603 
hasMessages(Handler h, int what, Object object)604     boolean hasMessages(Handler h, int what, Object object) {
605         if (h == null) {
606             return false;
607         }
608 
609         synchronized (this) {
610             Message p = mMessages;
611             while (p != null) {
612                 if (p.target == h && p.what == what && (object == null || p.obj == object)) {
613                     return true;
614                 }
615                 p = p.next;
616             }
617             return false;
618         }
619     }
620 
hasEqualMessages(Handler h, int what, Object object)621     boolean hasEqualMessages(Handler h, int what, Object object) {
622         if (h == null) {
623             return false;
624         }
625 
626         synchronized (this) {
627             Message p = mMessages;
628             while (p != null) {
629                 if (p.target == h && p.what == what && (object == null || object.equals(p.obj))) {
630                     return true;
631                 }
632                 p = p.next;
633             }
634             return false;
635         }
636     }
637 
638     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
hasMessages(Handler h, Runnable r, Object object)639     boolean hasMessages(Handler h, Runnable r, Object object) {
640         if (h == null) {
641             return false;
642         }
643 
644         synchronized (this) {
645             Message p = mMessages;
646             while (p != null) {
647                 if (p.target == h && p.callback == r && (object == null || p.obj == object)) {
648                     return true;
649                 }
650                 p = p.next;
651             }
652             return false;
653         }
654     }
655 
hasMessages(Handler h)656     boolean hasMessages(Handler h) {
657         if (h == null) {
658             return false;
659         }
660 
661         synchronized (this) {
662             Message p = mMessages;
663             while (p != null) {
664                 if (p.target == h) {
665                     return true;
666                 }
667                 p = p.next;
668             }
669             return false;
670         }
671     }
672 
removeMessages(Handler h, int what, Object object)673     void removeMessages(Handler h, int what, Object object) {
674         if (h == null) {
675             return;
676         }
677 
678         synchronized (this) {
679             Message p = mMessages;
680 
681             // Remove all messages at front.
682             while (p != null && p.target == h && p.what == what
683                    && (object == null || p.obj == object)) {
684                 Message n = p.next;
685                 mMessages = n;
686                 p.recycleUnchecked();
687                 p = n;
688             }
689 
690             // Remove all messages after front.
691             while (p != null) {
692                 Message n = p.next;
693                 if (n != null) {
694                     if (n.target == h && n.what == what
695                         && (object == null || n.obj == object)) {
696                         Message nn = n.next;
697                         n.recycleUnchecked();
698                         p.next = nn;
699                         continue;
700                     }
701                 }
702                 p = n;
703             }
704         }
705     }
706 
removeEqualMessages(Handler h, int what, Object object)707     void removeEqualMessages(Handler h, int what, Object object) {
708         if (h == null) {
709             return;
710         }
711 
712         synchronized (this) {
713             Message p = mMessages;
714 
715             // Remove all messages at front.
716             while (p != null && p.target == h && p.what == what
717                    && (object == null || object.equals(p.obj))) {
718                 Message n = p.next;
719                 mMessages = n;
720                 p.recycleUnchecked();
721                 p = n;
722             }
723 
724             // Remove all messages after front.
725             while (p != null) {
726                 Message n = p.next;
727                 if (n != null) {
728                     if (n.target == h && n.what == what
729                         && (object == null || object.equals(n.obj))) {
730                         Message nn = n.next;
731                         n.recycleUnchecked();
732                         p.next = nn;
733                         continue;
734                     }
735                 }
736                 p = n;
737             }
738         }
739     }
740 
removeMessages(Handler h, Runnable r, Object object)741     void removeMessages(Handler h, Runnable r, Object object) {
742         if (h == null || r == null) {
743             return;
744         }
745 
746         synchronized (this) {
747             Message p = mMessages;
748 
749             // Remove all messages at front.
750             while (p != null && p.target == h && p.callback == r
751                    && (object == null || p.obj == object)) {
752                 Message n = p.next;
753                 mMessages = n;
754                 p.recycleUnchecked();
755                 p = n;
756             }
757 
758             // Remove all messages after front.
759             while (p != null) {
760                 Message n = p.next;
761                 if (n != null) {
762                     if (n.target == h && n.callback == r
763                         && (object == null || n.obj == object)) {
764                         Message nn = n.next;
765                         n.recycleUnchecked();
766                         p.next = nn;
767                         continue;
768                     }
769                 }
770                 p = n;
771             }
772         }
773     }
774 
removeEqualMessages(Handler h, Runnable r, Object object)775     void removeEqualMessages(Handler h, Runnable r, Object object) {
776         if (h == null || r == null) {
777             return;
778         }
779 
780         synchronized (this) {
781             Message p = mMessages;
782 
783             // Remove all messages at front.
784             while (p != null && p.target == h && p.callback == r
785                    && (object == null || object.equals(p.obj))) {
786                 Message n = p.next;
787                 mMessages = n;
788                 p.recycleUnchecked();
789                 p = n;
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.callback == r
797                         && (object == null || object.equals(n.obj))) {
798                         Message nn = n.next;
799                         n.recycleUnchecked();
800                         p.next = nn;
801                         continue;
802                     }
803                 }
804                 p = n;
805             }
806         }
807     }
808 
809 
removeCallbacksAndMessages(Handler h, Object object)810     void removeCallbacksAndMessages(Handler h, Object object) {
811         if (h == null) {
812             return;
813         }
814 
815         synchronized (this) {
816             Message p = mMessages;
817 
818             // Remove all messages at front.
819             while (p != null && p.target == h
820                     && (object == null || p.obj == object)) {
821                 Message n = p.next;
822                 mMessages = n;
823                 p.recycleUnchecked();
824                 p = n;
825             }
826 
827             // Remove all messages after front.
828             while (p != null) {
829                 Message n = p.next;
830                 if (n != null) {
831                     if (n.target == h && (object == null || n.obj == object)) {
832                         Message nn = n.next;
833                         n.recycleUnchecked();
834                         p.next = nn;
835                         continue;
836                     }
837                 }
838                 p = n;
839             }
840         }
841     }
842 
removeCallbacksAndEqualMessages(Handler h, Object object)843     void removeCallbacksAndEqualMessages(Handler h, Object object) {
844         if (h == null) {
845             return;
846         }
847 
848         synchronized (this) {
849             Message p = mMessages;
850 
851             // Remove all messages at front.
852             while (p != null && p.target == h
853                     && (object == null || object.equals(p.obj))) {
854                 Message n = p.next;
855                 mMessages = n;
856                 p.recycleUnchecked();
857                 p = n;
858             }
859 
860             // Remove all messages after front.
861             while (p != null) {
862                 Message n = p.next;
863                 if (n != null) {
864                     if (n.target == h && (object == null || object.equals(n.obj))) {
865                         Message nn = n.next;
866                         n.recycleUnchecked();
867                         p.next = nn;
868                         continue;
869                     }
870                 }
871                 p = n;
872             }
873         }
874     }
875 
removeAllMessagesLocked()876     private void removeAllMessagesLocked() {
877         Message p = mMessages;
878         while (p != null) {
879             Message n = p.next;
880             p.recycleUnchecked();
881             p = n;
882         }
883         mMessages = null;
884     }
885 
removeAllFutureMessagesLocked()886     private void removeAllFutureMessagesLocked() {
887         final long now = SystemClock.uptimeMillis();
888         Message p = mMessages;
889         if (p != null) {
890             if (p.when > now) {
891                 removeAllMessagesLocked();
892             } else {
893                 Message n;
894                 for (;;) {
895                     n = p.next;
896                     if (n == null) {
897                         return;
898                     }
899                     if (n.when > now) {
900                         break;
901                     }
902                     p = n;
903                 }
904                 p.next = null;
905                 do {
906                     p = n;
907                     n = p.next;
908                     p.recycleUnchecked();
909                 } while (n != null);
910             }
911         }
912     }
913 
dump(Printer pw, String prefix, Handler h)914     void dump(Printer pw, String prefix, Handler h) {
915         synchronized (this) {
916             long now = SystemClock.uptimeMillis();
917             int n = 0;
918             for (Message msg = mMessages; msg != null; msg = msg.next) {
919                 if (h == null || h == msg.target) {
920                     pw.println(prefix + "Message " + n + ": " + msg.toString(now));
921                 }
922                 n++;
923             }
924             pw.println(prefix + "(Total messages: " + n + ", polling=" + isPollingLocked()
925                     + ", quitting=" + mQuitting + ")");
926         }
927     }
928 
dumpDebug(ProtoOutputStream proto, long fieldId)929     void dumpDebug(ProtoOutputStream proto, long fieldId) {
930         final long messageQueueToken = proto.start(fieldId);
931         synchronized (this) {
932             for (Message msg = mMessages; msg != null; msg = msg.next) {
933                 msg.dumpDebug(proto, MessageQueueProto.MESSAGES);
934             }
935             proto.write(MessageQueueProto.IS_POLLING_LOCKED, isPollingLocked());
936             proto.write(MessageQueueProto.IS_QUITTING, mQuitting);
937         }
938         proto.end(messageQueueToken);
939     }
940 
941     /**
942      * Callback interface for discovering when a thread is going to block
943      * waiting for more messages.
944      */
945     public static interface IdleHandler {
946         /**
947          * Called when the message queue has run out of messages and will now
948          * wait for more.  Return true to keep your idle handler active, false
949          * to have it removed.  This may be called if there are still messages
950          * pending in the queue, but they are all scheduled to be dispatched
951          * after the current time.
952          */
queueIdle()953         boolean queueIdle();
954     }
955 
956     /**
957      * A listener which is invoked when file descriptor related events occur.
958      */
959     public interface OnFileDescriptorEventListener {
960         /**
961          * File descriptor event: Indicates that the file descriptor is ready for input
962          * operations, such as reading.
963          * <p>
964          * The listener should read all available data from the file descriptor
965          * then return <code>true</code> to keep the listener active or <code>false</code>
966          * to remove the listener.
967          * </p><p>
968          * In the case of a socket, this event may be generated to indicate
969          * that there is at least one incoming connection that the listener
970          * should accept.
971          * </p><p>
972          * This event will only be generated if the {@link #EVENT_INPUT} event mask was
973          * specified when the listener was added.
974          * </p>
975          */
976         public static final int EVENT_INPUT = 1 << 0;
977 
978         /**
979          * File descriptor event: Indicates that the file descriptor is ready for output
980          * operations, such as writing.
981          * <p>
982          * The listener should write as much data as it needs.  If it could not
983          * write everything at once, then it should return <code>true</code> to
984          * keep the listener active.  Otherwise, it should return <code>false</code>
985          * to remove the listener then re-register it later when it needs to write
986          * something else.
987          * </p><p>
988          * This event will only be generated if the {@link #EVENT_OUTPUT} event mask was
989          * specified when the listener was added.
990          * </p>
991          */
992         public static final int EVENT_OUTPUT = 1 << 1;
993 
994         /**
995          * File descriptor event: Indicates that the file descriptor encountered a
996          * fatal error.
997          * <p>
998          * File descriptor errors can occur for various reasons.  One common error
999          * is when the remote peer of a socket or pipe closes its end of the connection.
1000          * </p><p>
1001          * This event may be generated at any time regardless of whether the
1002          * {@link #EVENT_ERROR} event mask was specified when the listener was added.
1003          * </p>
1004          */
1005         public static final int EVENT_ERROR = 1 << 2;
1006 
1007         /** @hide */
1008         @Retention(RetentionPolicy.SOURCE)
1009         @IntDef(flag = true, prefix = { "EVENT_" }, value = {
1010                 EVENT_INPUT,
1011                 EVENT_OUTPUT,
1012                 EVENT_ERROR
1013         })
1014         public @interface Events {}
1015 
1016         /**
1017          * Called when a file descriptor receives events.
1018          *
1019          * @param fd The file descriptor.
1020          * @param events The set of events that occurred: a combination of the
1021          * {@link #EVENT_INPUT}, {@link #EVENT_OUTPUT}, and {@link #EVENT_ERROR} event masks.
1022          * @return The new set of events to watch, or 0 to unregister the listener.
1023          *
1024          * @see #EVENT_INPUT
1025          * @see #EVENT_OUTPUT
1026          * @see #EVENT_ERROR
1027          */
onFileDescriptorEvents(@onNull FileDescriptor fd, @Events int events)1028         @Events int onFileDescriptorEvents(@NonNull FileDescriptor fd, @Events int events);
1029     }
1030 
1031     private static final class FileDescriptorRecord {
1032         public final FileDescriptor mDescriptor;
1033         public int mEvents;
1034         public OnFileDescriptorEventListener mListener;
1035         public int mSeq;
1036 
FileDescriptorRecord(FileDescriptor descriptor, int events, OnFileDescriptorEventListener listener)1037         public FileDescriptorRecord(FileDescriptor descriptor,
1038                 int events, OnFileDescriptorEventListener listener) {
1039             mDescriptor = descriptor;
1040             mEvents = events;
1041             mListener = listener;
1042         }
1043     }
1044 }
1045