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