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