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