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 nativeInit()70 private native static long nativeInit(); nativeDestroy(long ptr)71 private native static void nativeDestroy(long ptr); 72 @UnsupportedAppUsage nativePollOnce(long ptr, int timeoutMillis)73 private native void nativePollOnce(long ptr, int timeoutMillis); /*non-static for callbacks*/ nativeWake(long ptr)74 private native static void nativeWake(long ptr); nativeIsPolling(long ptr)75 private native static boolean nativeIsPolling(long ptr); nativeSetFileDescriptorEvents(long ptr, int fd, int events)76 private native static void nativeSetFileDescriptorEvents(long ptr, int fd, int events); 77 MessageQueue(boolean quitAllowed)78 MessageQueue(boolean quitAllowed) { 79 mQuitAllowed = quitAllowed; 80 mPtr = nativeInit(); 81 } 82 83 @Override finalize()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. dispose()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 */ isIdle()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 */ addIdleHandler(@onNull IdleHandler handler)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 */ removeIdleHandler(@onNull IdleHandler handler)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 */ isPolling()160 public boolean isPolling() { 161 synchronized (this) { 162 return isPollingLocked(); 163 } 164 } 165 isPollingLocked()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 */ addOnFileDescriptorEventListener(@onNull FileDescriptor fd, @OnFileDescriptorEventListener.Events int events, @NonNull OnFileDescriptorEventListener listener)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 */ removeOnFileDescriptorEventListener(@onNull FileDescriptor fd)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 updateOnFileDescriptorEventListenerLocked(FileDescriptor fd, int events, OnFileDescriptorEventListener listener)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 dispatchEvents(int fd, int events)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 next()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 quit(boolean safe)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 postSyncBarrier()472 public int postSyncBarrier() { 473 return postSyncBarrier(SystemClock.uptimeMillis()); 474 } 475 postSyncBarrier(long when)476 private int postSyncBarrier(long when) { 477 // Enqueue a new sync barrier token. 478 // We don't need to wake the queue because the purpose of a barrier is to stall it. 479 synchronized (this) { 480 final int token = mNextBarrierToken++; 481 final Message msg = Message.obtain(); 482 msg.markInUse(); 483 msg.when = when; 484 msg.arg1 = token; 485 486 Message prev = null; 487 Message p = mMessages; 488 if (when != 0) { 489 while (p != null && p.when <= when) { 490 prev = p; 491 p = p.next; 492 } 493 } 494 if (prev != null) { // invariant: p == prev.next 495 msg.next = p; 496 prev.next = msg; 497 } else { 498 msg.next = p; 499 mMessages = msg; 500 } 501 return token; 502 } 503 } 504 505 /** 506 * Removes a synchronization barrier. 507 * 508 * @param token The synchronization barrier token that was returned by 509 * {@link #postSyncBarrier}. 510 * 511 * @throws IllegalStateException if the barrier was not found. 512 * 513 * @hide 514 */ 515 @TestApi removeSyncBarrier(int token)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 enqueueMessage(Message msg, long when)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 hasMessages(Handler h, int what, Object object)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 hasMessages(Handler h, Runnable r, Object object)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 hasMessages(Handler h)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 removeMessages(Handler h, int what, Object object)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 removeMessages(Handler h, Runnable r, Object object)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 removeCallbacksAndMessages(Handler h, Object object)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 removeAllMessagesLocked()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 removeAllFutureMessagesLocked()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 dump(Printer pw, String prefix, Handler h)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 writeToProto(ProtoOutputStream proto, long fieldId)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 */ queueIdle()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 */ onFileDescriptorEvents(@onNull FileDescriptor fd, @Events int events)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 FileDescriptorRecord(FileDescriptor descriptor, int events, OnFileDescriptorEventListener listener)916 public FileDescriptorRecord(FileDescriptor descriptor, 917 int events, OnFileDescriptorEventListener listener) { 918 mDescriptor = descriptor; 919 mEvents = events; 920 mListener = listener; 921 } 922 } 923 } 924