• 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.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         }
258     }
259 
260     // Called from native code.
dispatchEvents(int fd, int events)261     private int dispatchEvents(int fd, int events) {
262         // Get the file descriptor record and any state that might change.
263         final FileDescriptorRecord record;
264         final int oldWatchedEvents;
265         final OnFileDescriptorEventListener listener;
266         final int seq;
267         synchronized (this) {
268             record = mFileDescriptorRecords.get(fd);
269             if (record == null) {
270                 return 0; // spurious, no listener registered
271             }
272 
273             oldWatchedEvents = record.mEvents;
274             events &= oldWatchedEvents; // filter events based on current watched set
275             if (events == 0) {
276                 return oldWatchedEvents; // spurious, watched events changed
277             }
278 
279             listener = record.mListener;
280             seq = record.mSeq;
281         }
282 
283         // Invoke the listener outside of the lock.
284         int newWatchedEvents = listener.onFileDescriptorEvents(
285                 record.mDescriptor, events);
286         if (newWatchedEvents != 0) {
287             newWatchedEvents |= OnFileDescriptorEventListener.EVENT_ERROR;
288         }
289 
290         // Update the file descriptor record if the listener changed the set of
291         // events to watch and the listener itself hasn't been updated since.
292         if (newWatchedEvents != oldWatchedEvents) {
293             synchronized (this) {
294                 int index = mFileDescriptorRecords.indexOfKey(fd);
295                 if (index >= 0 && mFileDescriptorRecords.valueAt(index) == record
296                         && record.mSeq == seq) {
297                     record.mEvents = newWatchedEvents;
298                     if (newWatchedEvents == 0) {
299                         mFileDescriptorRecords.removeAt(index);
300                     }
301                 }
302             }
303         }
304 
305         // Return the new set of events to watch for native code to take care of.
306         return newWatchedEvents;
307     }
308 
next()309     Message next() {
310         // Return here if the message loop has already quit and been disposed.
311         // This can happen if the application tries to restart a looper after quit
312         // which is not supported.
313         final long ptr = mPtr;
314         if (ptr == 0) {
315             return null;
316         }
317 
318         int pendingIdleHandlerCount = -1; // -1 only during first iteration
319         int nextPollTimeoutMillis = 0;
320         for (;;) {
321             if (nextPollTimeoutMillis != 0) {
322                 Binder.flushPendingCommands();
323             }
324 
325             nativePollOnce(ptr, nextPollTimeoutMillis);
326 
327             synchronized (this) {
328                 // Try to retrieve the next message.  Return if found.
329                 final long now = SystemClock.uptimeMillis();
330                 Message prevMsg = null;
331                 Message msg = mMessages;
332                 if (msg != null && msg.target == null) {
333                     // Stalled by a barrier.  Find the next asynchronous message in the queue.
334                     do {
335                         prevMsg = msg;
336                         msg = msg.next;
337                     } while (msg != null && !msg.isAsynchronous());
338                 }
339                 if (msg != null) {
340                     if (now < msg.when) {
341                         // Next message is not ready.  Set a timeout to wake up when it is ready.
342                         nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
343                     } else {
344                         // Got a message.
345                         mBlocked = false;
346                         if (prevMsg != null) {
347                             prevMsg.next = msg.next;
348                         } else {
349                             mMessages = msg.next;
350                         }
351                         msg.next = null;
352                         if (DEBUG) Log.v(TAG, "Returning message: " + msg);
353                         msg.markInUse();
354                         return msg;
355                     }
356                 } else {
357                     // No more messages.
358                     nextPollTimeoutMillis = -1;
359                 }
360 
361                 // Process the quit message now that all pending messages have been handled.
362                 if (mQuitting) {
363                     dispose();
364                     return null;
365                 }
366 
367                 // If first time idle, then get the number of idlers to run.
368                 // Idle handles only run if the queue is empty or if the first message
369                 // in the queue (possibly a barrier) is due to be handled in the future.
370                 if (pendingIdleHandlerCount < 0
371                         && (mMessages == null || now < mMessages.when)) {
372                     pendingIdleHandlerCount = mIdleHandlers.size();
373                 }
374                 if (pendingIdleHandlerCount <= 0) {
375                     // No idle handlers to run.  Loop and wait some more.
376                     mBlocked = true;
377                     continue;
378                 }
379 
380                 if (mPendingIdleHandlers == null) {
381                     mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
382                 }
383                 mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
384             }
385 
386             // Run the idle handlers.
387             // We only ever reach this code block during the first iteration.
388             for (int i = 0; i < pendingIdleHandlerCount; i++) {
389                 final IdleHandler idler = mPendingIdleHandlers[i];
390                 mPendingIdleHandlers[i] = null; // release the reference to the handler
391 
392                 boolean keep = false;
393                 try {
394                     keep = idler.queueIdle();
395                 } catch (Throwable t) {
396                     Log.wtf(TAG, "IdleHandler threw exception", t);
397                 }
398 
399                 if (!keep) {
400                     synchronized (this) {
401                         mIdleHandlers.remove(idler);
402                     }
403                 }
404             }
405 
406             // Reset the idle handler count to 0 so we do not run them again.
407             pendingIdleHandlerCount = 0;
408 
409             // While calling an idle handler, a new message could have been delivered
410             // so go back and look again for a pending message without waiting.
411             nextPollTimeoutMillis = 0;
412         }
413     }
414 
quit(boolean safe)415     void quit(boolean safe) {
416         if (!mQuitAllowed) {
417             throw new IllegalStateException("Main thread not allowed to quit.");
418         }
419 
420         synchronized (this) {
421             if (mQuitting) {
422                 return;
423             }
424             mQuitting = true;
425 
426             if (safe) {
427                 removeAllFutureMessagesLocked();
428             } else {
429                 removeAllMessagesLocked();
430             }
431 
432             // We can assume mPtr != 0 because mQuitting was previously false.
433             nativeWake(mPtr);
434         }
435     }
436 
437     /**
438      * Posts a synchronization barrier to the Looper's message queue.
439      *
440      * Message processing occurs as usual until the message queue encounters the
441      * synchronization barrier that has been posted.  When the barrier is encountered,
442      * later synchronous messages in the queue are stalled (prevented from being executed)
443      * until the barrier is released by calling {@link #removeSyncBarrier} and specifying
444      * the token that identifies the synchronization barrier.
445      *
446      * This method is used to immediately postpone execution of all subsequently posted
447      * synchronous messages until a condition is met that releases the barrier.
448      * Asynchronous messages (see {@link Message#isAsynchronous} are exempt from the barrier
449      * and continue to be processed as usual.
450      *
451      * This call must be always matched by a call to {@link #removeSyncBarrier} with
452      * the same token to ensure that the message queue resumes normal operation.
453      * Otherwise the application will probably hang!
454      *
455      * @return A token that uniquely identifies the barrier.  This token must be
456      * passed to {@link #removeSyncBarrier} to release the barrier.
457      *
458      * @hide
459      */
postSyncBarrier()460     public int postSyncBarrier() {
461         return postSyncBarrier(SystemClock.uptimeMillis());
462     }
463 
postSyncBarrier(long when)464     private int postSyncBarrier(long when) {
465         // Enqueue a new sync barrier token.
466         // We don't need to wake the queue because the purpose of a barrier is to stall it.
467         synchronized (this) {
468             final int token = mNextBarrierToken++;
469             final Message msg = Message.obtain();
470             msg.markInUse();
471             msg.when = when;
472             msg.arg1 = token;
473 
474             Message prev = null;
475             Message p = mMessages;
476             if (when != 0) {
477                 while (p != null && p.when <= when) {
478                     prev = p;
479                     p = p.next;
480                 }
481             }
482             if (prev != null) { // invariant: p == prev.next
483                 msg.next = p;
484                 prev.next = msg;
485             } else {
486                 msg.next = p;
487                 mMessages = msg;
488             }
489             return token;
490         }
491     }
492 
493     /**
494      * Removes a synchronization barrier.
495      *
496      * @param token The synchronization barrier token that was returned by
497      * {@link #postSyncBarrier}.
498      *
499      * @throws IllegalStateException if the barrier was not found.
500      *
501      * @hide
502      */
removeSyncBarrier(int token)503     public void removeSyncBarrier(int token) {
504         // Remove a sync barrier token from the queue.
505         // If the queue is no longer stalled by a barrier then wake it.
506         synchronized (this) {
507             Message prev = null;
508             Message p = mMessages;
509             while (p != null && (p.target != null || p.arg1 != token)) {
510                 prev = p;
511                 p = p.next;
512             }
513             if (p == null) {
514                 throw new IllegalStateException("The specified message queue synchronization "
515                         + " barrier token has not been posted or has already been removed.");
516             }
517             final boolean needWake;
518             if (prev != null) {
519                 prev.next = p.next;
520                 needWake = false;
521             } else {
522                 mMessages = p.next;
523                 needWake = mMessages == null || mMessages.target != null;
524             }
525             p.recycleUnchecked();
526 
527             // If the loop is quitting then it is already awake.
528             // We can assume mPtr != 0 when mQuitting is false.
529             if (needWake && !mQuitting) {
530                 nativeWake(mPtr);
531             }
532         }
533     }
534 
enqueueMessage(Message msg, long when)535     boolean enqueueMessage(Message msg, long when) {
536         if (msg.target == null) {
537             throw new IllegalArgumentException("Message must have a target.");
538         }
539         if (msg.isInUse()) {
540             throw new IllegalStateException(msg + " This message is already in use.");
541         }
542 
543         synchronized (this) {
544             if (mQuitting) {
545                 IllegalStateException e = new IllegalStateException(
546                         msg.target + " sending message to a Handler on a dead thread");
547                 Log.w(TAG, e.getMessage(), e);
548                 msg.recycle();
549                 return false;
550             }
551 
552             msg.markInUse();
553             msg.when = when;
554             Message p = mMessages;
555             boolean needWake;
556             if (p == null || when == 0 || when < p.when) {
557                 // New head, wake up the event queue if blocked.
558                 msg.next = p;
559                 mMessages = msg;
560                 needWake = mBlocked;
561             } else {
562                 // Inserted within the middle of the queue.  Usually we don't have to wake
563                 // up the event queue unless there is a barrier at the head of the queue
564                 // and the message is the earliest asynchronous message in the queue.
565                 needWake = mBlocked && p.target == null && msg.isAsynchronous();
566                 Message prev;
567                 for (;;) {
568                     prev = p;
569                     p = p.next;
570                     if (p == null || when < p.when) {
571                         break;
572                     }
573                     if (needWake && p.isAsynchronous()) {
574                         needWake = false;
575                     }
576                 }
577                 msg.next = p; // invariant: p == prev.next
578                 prev.next = msg;
579             }
580 
581             // We can assume mPtr != 0 because mQuitting is false.
582             if (needWake) {
583                 nativeWake(mPtr);
584             }
585         }
586         return true;
587     }
588 
hasMessages(Handler h, int what, Object object)589     boolean hasMessages(Handler h, int what, Object object) {
590         if (h == null) {
591             return false;
592         }
593 
594         synchronized (this) {
595             Message p = mMessages;
596             while (p != null) {
597                 if (p.target == h && p.what == what && (object == null || p.obj == object)) {
598                     return true;
599                 }
600                 p = p.next;
601             }
602             return false;
603         }
604     }
605 
hasMessages(Handler h, Runnable r, Object object)606     boolean hasMessages(Handler h, Runnable r, Object object) {
607         if (h == null) {
608             return false;
609         }
610 
611         synchronized (this) {
612             Message p = mMessages;
613             while (p != null) {
614                 if (p.target == h && p.callback == r && (object == null || p.obj == object)) {
615                     return true;
616                 }
617                 p = p.next;
618             }
619             return false;
620         }
621     }
622 
hasMessages(Handler h)623     boolean hasMessages(Handler h) {
624         if (h == null) {
625             return false;
626         }
627 
628         synchronized (this) {
629             Message p = mMessages;
630             while (p != null) {
631                 if (p.target == h) {
632                     return true;
633                 }
634                 p = p.next;
635             }
636             return false;
637         }
638     }
639 
removeMessages(Handler h, int what, Object object)640     void removeMessages(Handler h, int what, Object object) {
641         if (h == null) {
642             return;
643         }
644 
645         synchronized (this) {
646             Message p = mMessages;
647 
648             // Remove all messages at front.
649             while (p != null && p.target == h && p.what == what
650                    && (object == null || p.obj == object)) {
651                 Message n = p.next;
652                 mMessages = n;
653                 p.recycleUnchecked();
654                 p = n;
655             }
656 
657             // Remove all messages after front.
658             while (p != null) {
659                 Message n = p.next;
660                 if (n != null) {
661                     if (n.target == h && n.what == what
662                         && (object == null || n.obj == object)) {
663                         Message nn = n.next;
664                         n.recycleUnchecked();
665                         p.next = nn;
666                         continue;
667                     }
668                 }
669                 p = n;
670             }
671         }
672     }
673 
removeMessages(Handler h, Runnable r, Object object)674     void removeMessages(Handler h, Runnable r, Object object) {
675         if (h == null || r == null) {
676             return;
677         }
678 
679         synchronized (this) {
680             Message p = mMessages;
681 
682             // Remove all messages at front.
683             while (p != null && p.target == h && p.callback == r
684                    && (object == null || p.obj == object)) {
685                 Message n = p.next;
686                 mMessages = n;
687                 p.recycleUnchecked();
688                 p = n;
689             }
690 
691             // Remove all messages after front.
692             while (p != null) {
693                 Message n = p.next;
694                 if (n != null) {
695                     if (n.target == h && n.callback == r
696                         && (object == null || n.obj == object)) {
697                         Message nn = n.next;
698                         n.recycleUnchecked();
699                         p.next = nn;
700                         continue;
701                     }
702                 }
703                 p = n;
704             }
705         }
706     }
707 
removeCallbacksAndMessages(Handler h, Object object)708     void removeCallbacksAndMessages(Handler h, Object object) {
709         if (h == null) {
710             return;
711         }
712 
713         synchronized (this) {
714             Message p = mMessages;
715 
716             // Remove all messages at front.
717             while (p != null && p.target == h
718                     && (object == null || p.obj == object)) {
719                 Message n = p.next;
720                 mMessages = n;
721                 p.recycleUnchecked();
722                 p = n;
723             }
724 
725             // Remove all messages after front.
726             while (p != null) {
727                 Message n = p.next;
728                 if (n != null) {
729                     if (n.target == h && (object == null || n.obj == object)) {
730                         Message nn = n.next;
731                         n.recycleUnchecked();
732                         p.next = nn;
733                         continue;
734                     }
735                 }
736                 p = n;
737             }
738         }
739     }
740 
removeAllMessagesLocked()741     private void removeAllMessagesLocked() {
742         Message p = mMessages;
743         while (p != null) {
744             Message n = p.next;
745             p.recycleUnchecked();
746             p = n;
747         }
748         mMessages = null;
749     }
750 
removeAllFutureMessagesLocked()751     private void removeAllFutureMessagesLocked() {
752         final long now = SystemClock.uptimeMillis();
753         Message p = mMessages;
754         if (p != null) {
755             if (p.when > now) {
756                 removeAllMessagesLocked();
757             } else {
758                 Message n;
759                 for (;;) {
760                     n = p.next;
761                     if (n == null) {
762                         return;
763                     }
764                     if (n.when > now) {
765                         break;
766                     }
767                     p = n;
768                 }
769                 p.next = null;
770                 do {
771                     p = n;
772                     n = p.next;
773                     p.recycleUnchecked();
774                 } while (n != null);
775             }
776         }
777     }
778 
dump(Printer pw, String prefix, Handler h)779     void dump(Printer pw, String prefix, Handler h) {
780         synchronized (this) {
781             long now = SystemClock.uptimeMillis();
782             int n = 0;
783             for (Message msg = mMessages; msg != null; msg = msg.next) {
784                 if (h == null || h == msg.target) {
785                     pw.println(prefix + "Message " + n + ": " + msg.toString(now));
786                 }
787                 n++;
788             }
789             pw.println(prefix + "(Total messages: " + n + ", polling=" + isPollingLocked()
790                     + ", quitting=" + mQuitting + ")");
791         }
792     }
793 
writeToProto(ProtoOutputStream proto, long fieldId)794     void writeToProto(ProtoOutputStream proto, long fieldId) {
795         final long messageQueueToken = proto.start(fieldId);
796         synchronized (this) {
797             for (Message msg = mMessages; msg != null; msg = msg.next) {
798                 msg.writeToProto(proto, MessageQueueProto.MESSAGES);
799             }
800             proto.write(MessageQueueProto.IS_POLLING_LOCKED, isPollingLocked());
801             proto.write(MessageQueueProto.IS_QUITTING, mQuitting);
802         }
803         proto.end(messageQueueToken);
804     }
805 
806     /**
807      * Callback interface for discovering when a thread is going to block
808      * waiting for more messages.
809      */
810     public static interface IdleHandler {
811         /**
812          * Called when the message queue has run out of messages and will now
813          * wait for more.  Return true to keep your idle handler active, false
814          * to have it removed.  This may be called if there are still messages
815          * pending in the queue, but they are all scheduled to be dispatched
816          * after the current time.
817          */
queueIdle()818         boolean queueIdle();
819     }
820 
821     /**
822      * A listener which is invoked when file descriptor related events occur.
823      */
824     public interface OnFileDescriptorEventListener {
825         /**
826          * File descriptor event: Indicates that the file descriptor is ready for input
827          * operations, such as reading.
828          * <p>
829          * The listener should read all available data from the file descriptor
830          * then return <code>true</code> to keep the listener active or <code>false</code>
831          * to remove the listener.
832          * </p><p>
833          * In the case of a socket, this event may be generated to indicate
834          * that there is at least one incoming connection that the listener
835          * should accept.
836          * </p><p>
837          * This event will only be generated if the {@link #EVENT_INPUT} event mask was
838          * specified when the listener was added.
839          * </p>
840          */
841         public static final int EVENT_INPUT = 1 << 0;
842 
843         /**
844          * File descriptor event: Indicates that the file descriptor is ready for output
845          * operations, such as writing.
846          * <p>
847          * The listener should write as much data as it needs.  If it could not
848          * write everything at once, then it should return <code>true</code> to
849          * keep the listener active.  Otherwise, it should return <code>false</code>
850          * to remove the listener then re-register it later when it needs to write
851          * something else.
852          * </p><p>
853          * This event will only be generated if the {@link #EVENT_OUTPUT} event mask was
854          * specified when the listener was added.
855          * </p>
856          */
857         public static final int EVENT_OUTPUT = 1 << 1;
858 
859         /**
860          * File descriptor event: Indicates that the file descriptor encountered a
861          * fatal error.
862          * <p>
863          * File descriptor errors can occur for various reasons.  One common error
864          * is when the remote peer of a socket or pipe closes its end of the connection.
865          * </p><p>
866          * This event may be generated at any time regardless of whether the
867          * {@link #EVENT_ERROR} event mask was specified when the listener was added.
868          * </p>
869          */
870         public static final int EVENT_ERROR = 1 << 2;
871 
872         /** @hide */
873         @Retention(RetentionPolicy.SOURCE)
874         @IntDef(flag=true, value={EVENT_INPUT, EVENT_OUTPUT, EVENT_ERROR})
875         public @interface Events {}
876 
877         /**
878          * Called when a file descriptor receives events.
879          *
880          * @param fd The file descriptor.
881          * @param events The set of events that occurred: a combination of the
882          * {@link #EVENT_INPUT}, {@link #EVENT_OUTPUT}, and {@link #EVENT_ERROR} event masks.
883          * @return The new set of events to watch, or 0 to unregister the listener.
884          *
885          * @see #EVENT_INPUT
886          * @see #EVENT_OUTPUT
887          * @see #EVENT_ERROR
888          */
onFileDescriptorEvents(@onNull FileDescriptor fd, @Events int events)889         @Events int onFileDescriptorEvents(@NonNull FileDescriptor fd, @Events int events);
890     }
891 
892     private static final class FileDescriptorRecord {
893         public final FileDescriptor mDescriptor;
894         public int mEvents;
895         public OnFileDescriptorEventListener mListener;
896         public int mSeq;
897 
FileDescriptorRecord(FileDescriptor descriptor, int events, OnFileDescriptorEventListener listener)898         public FileDescriptorRecord(FileDescriptor descriptor,
899                 int events, OnFileDescriptorEventListener listener) {
900             mDescriptor = descriptor;
901             mEvents = events;
902             mListener = listener;
903         }
904     }
905 }
906