Home | History | Annotate | Download | only in os
      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 
     63     private native static long nativeInit();
     64     private native static void nativeDestroy(long ptr);
     65     private native void nativePollOnce(long ptr, int timeoutMillis); /*non-static for callbacks*/
     66     private native static void nativeWake(long ptr);
     67     private native static boolean nativeIsPolling(long ptr);
     68     private native static void nativeSetFileDescriptorEvents(long ptr, int fd, int events);
     69 
     70     MessageQueue(boolean quitAllowed) {
     71         mQuitAllowed = quitAllowed;
     72         mPtr = nativeInit();
     73     }
     74 
     75     @Override
     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.
     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      */
    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      */
    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      */
    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      */
    152     public boolean isPolling() {
    153         synchronized (this) {
    154             return isPollingLocked();
    155         }
    156     }
    157 
    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      */
    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      */
    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 
    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.
    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 
    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 
    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      */
    461     public int postSyncBarrier() {
    462         return postSyncBarrier(SystemClock.uptimeMillis());
    463     }
    464 
    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      */
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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          */
    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          */
    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 
    903         public FileDescriptorRecord(FileDescriptor descriptor,
    904                 int events, OnFileDescriptorEventListener listener) {
    905             mDescriptor = descriptor;
    906             mEvents = events;
    907             mListener = listener;
    908         }
    909     }
    910 }
    911