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