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 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 if (msg.isInUse()) { 554 throw new IllegalStateException(msg + " This message is already in use."); 555 } 556 557 synchronized (this) { 558 if (mQuitting) { 559 IllegalStateException e = new IllegalStateException( 560 msg.target + " sending message to a Handler on a dead thread"); 561 Log.w(TAG, e.getMessage(), e); 562 msg.recycle(); 563 return false; 564 } 565 566 msg.markInUse(); 567 msg.when = when; 568 Message p = mMessages; 569 boolean needWake; 570 if (p == null || when == 0 || when < p.when) { 571 // New head, wake up the event queue if blocked. 572 msg.next = p; 573 mMessages = msg; 574 needWake = mBlocked; 575 } else { 576 // Inserted within the middle of the queue. Usually we don't have to wake 577 // up the event queue unless there is a barrier at the head of the queue 578 // and the message is the earliest asynchronous message in the queue. 579 needWake = mBlocked && p.target == null && msg.isAsynchronous(); 580 Message prev; 581 for (;;) { 582 prev = p; 583 p = p.next; 584 if (p == null || when < p.when) { 585 break; 586 } 587 if (needWake && p.isAsynchronous()) { 588 needWake = false; 589 } 590 } 591 msg.next = p; // invariant: p == prev.next 592 prev.next = msg; 593 } 594 595 // We can assume mPtr != 0 because mQuitting is false. 596 if (needWake) { 597 nativeWake(mPtr); 598 } 599 } 600 return true; 601 } 602 hasMessages(Handler h, int what, Object object)603 boolean hasMessages(Handler h, int what, Object object) { 604 if (h == null) { 605 return false; 606 } 607 608 synchronized (this) { 609 Message p = mMessages; 610 while (p != null) { 611 if (p.target == h && p.what == what && (object == null || p.obj == object)) { 612 return true; 613 } 614 p = p.next; 615 } 616 return false; 617 } 618 } 619 hasEqualMessages(Handler h, int what, Object object)620 boolean hasEqualMessages(Handler h, int what, 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.what == what && (object == null || object.equals(p.obj))) { 629 return true; 630 } 631 p = p.next; 632 } 633 return false; 634 } 635 } 636 637 @UnsupportedAppUsage hasMessages(Handler h, Runnable r, Object object)638 boolean hasMessages(Handler h, Runnable r, Object object) { 639 if (h == null) { 640 return false; 641 } 642 643 synchronized (this) { 644 Message p = mMessages; 645 while (p != null) { 646 if (p.target == h && p.callback == r && (object == null || p.obj == object)) { 647 return true; 648 } 649 p = p.next; 650 } 651 return false; 652 } 653 } 654 hasMessages(Handler h)655 boolean hasMessages(Handler h) { 656 if (h == null) { 657 return false; 658 } 659 660 synchronized (this) { 661 Message p = mMessages; 662 while (p != null) { 663 if (p.target == h) { 664 return true; 665 } 666 p = p.next; 667 } 668 return false; 669 } 670 } 671 removeMessages(Handler h, int what, Object object)672 void removeMessages(Handler h, int what, Object object) { 673 if (h == null) { 674 return; 675 } 676 677 synchronized (this) { 678 Message p = mMessages; 679 680 // Remove all messages at front. 681 while (p != null && p.target == h && p.what == what 682 && (object == null || p.obj == object)) { 683 Message n = p.next; 684 mMessages = n; 685 p.recycleUnchecked(); 686 p = n; 687 } 688 689 // Remove all messages after front. 690 while (p != null) { 691 Message n = p.next; 692 if (n != null) { 693 if (n.target == h && n.what == what 694 && (object == null || n.obj == object)) { 695 Message nn = n.next; 696 n.recycleUnchecked(); 697 p.next = nn; 698 continue; 699 } 700 } 701 p = n; 702 } 703 } 704 } 705 removeEqualMessages(Handler h, int what, Object object)706 void removeEqualMessages(Handler h, int what, Object object) { 707 if (h == null) { 708 return; 709 } 710 711 synchronized (this) { 712 Message p = mMessages; 713 714 // Remove all messages at front. 715 while (p != null && p.target == h && p.what == what 716 && (object == null || object.equals(p.obj))) { 717 Message n = p.next; 718 mMessages = n; 719 p.recycleUnchecked(); 720 p = n; 721 } 722 723 // Remove all messages after front. 724 while (p != null) { 725 Message n = p.next; 726 if (n != null) { 727 if (n.target == h && n.what == what 728 && (object == null || object.equals(n.obj))) { 729 Message nn = n.next; 730 n.recycleUnchecked(); 731 p.next = nn; 732 continue; 733 } 734 } 735 p = n; 736 } 737 } 738 } 739 removeMessages(Handler h, Runnable r, Object object)740 void removeMessages(Handler h, Runnable r, Object object) { 741 if (h == null || r == null) { 742 return; 743 } 744 745 synchronized (this) { 746 Message p = mMessages; 747 748 // Remove all messages at front. 749 while (p != null && p.target == h && p.callback == r 750 && (object == null || p.obj == object)) { 751 Message n = p.next; 752 mMessages = n; 753 p.recycleUnchecked(); 754 p = n; 755 } 756 757 // Remove all messages after front. 758 while (p != null) { 759 Message n = p.next; 760 if (n != null) { 761 if (n.target == h && n.callback == r 762 && (object == null || n.obj == object)) { 763 Message nn = n.next; 764 n.recycleUnchecked(); 765 p.next = nn; 766 continue; 767 } 768 } 769 p = n; 770 } 771 } 772 } 773 removeEqualMessages(Handler h, Runnable r, Object object)774 void removeEqualMessages(Handler h, Runnable r, Object object) { 775 if (h == null || r == null) { 776 return; 777 } 778 779 synchronized (this) { 780 Message p = mMessages; 781 782 // Remove all messages at front. 783 while (p != null && p.target == h && p.callback == r 784 && (object == null || object.equals(p.obj))) { 785 Message n = p.next; 786 mMessages = n; 787 p.recycleUnchecked(); 788 p = n; 789 } 790 791 // Remove all messages after front. 792 while (p != null) { 793 Message n = p.next; 794 if (n != null) { 795 if (n.target == h && n.callback == r 796 && (object == null || object.equals(n.obj))) { 797 Message nn = n.next; 798 n.recycleUnchecked(); 799 p.next = nn; 800 continue; 801 } 802 } 803 p = n; 804 } 805 } 806 } 807 808 removeCallbacksAndMessages(Handler h, Object object)809 void removeCallbacksAndMessages(Handler h, Object object) { 810 if (h == null) { 811 return; 812 } 813 814 synchronized (this) { 815 Message p = mMessages; 816 817 // Remove all messages at front. 818 while (p != null && p.target == h 819 && (object == null || p.obj == object)) { 820 Message n = p.next; 821 mMessages = n; 822 p.recycleUnchecked(); 823 p = n; 824 } 825 826 // Remove all messages after front. 827 while (p != null) { 828 Message n = p.next; 829 if (n != null) { 830 if (n.target == h && (object == null || n.obj == object)) { 831 Message nn = n.next; 832 n.recycleUnchecked(); 833 p.next = nn; 834 continue; 835 } 836 } 837 p = n; 838 } 839 } 840 } 841 removeCallbacksAndEqualMessages(Handler h, Object object)842 void removeCallbacksAndEqualMessages(Handler h, Object object) { 843 if (h == null) { 844 return; 845 } 846 847 synchronized (this) { 848 Message p = mMessages; 849 850 // Remove all messages at front. 851 while (p != null && p.target == h 852 && (object == null || object.equals(p.obj))) { 853 Message n = p.next; 854 mMessages = n; 855 p.recycleUnchecked(); 856 p = n; 857 } 858 859 // Remove all messages after front. 860 while (p != null) { 861 Message n = p.next; 862 if (n != null) { 863 if (n.target == h && (object == null || object.equals(n.obj))) { 864 Message nn = n.next; 865 n.recycleUnchecked(); 866 p.next = nn; 867 continue; 868 } 869 } 870 p = n; 871 } 872 } 873 } 874 removeAllMessagesLocked()875 private void removeAllMessagesLocked() { 876 Message p = mMessages; 877 while (p != null) { 878 Message n = p.next; 879 p.recycleUnchecked(); 880 p = n; 881 } 882 mMessages = null; 883 } 884 removeAllFutureMessagesLocked()885 private void removeAllFutureMessagesLocked() { 886 final long now = SystemClock.uptimeMillis(); 887 Message p = mMessages; 888 if (p != null) { 889 if (p.when > now) { 890 removeAllMessagesLocked(); 891 } else { 892 Message n; 893 for (;;) { 894 n = p.next; 895 if (n == null) { 896 return; 897 } 898 if (n.when > now) { 899 break; 900 } 901 p = n; 902 } 903 p.next = null; 904 do { 905 p = n; 906 n = p.next; 907 p.recycleUnchecked(); 908 } while (n != null); 909 } 910 } 911 } 912 dump(Printer pw, String prefix, Handler h)913 void dump(Printer pw, String prefix, Handler h) { 914 synchronized (this) { 915 long now = SystemClock.uptimeMillis(); 916 int n = 0; 917 for (Message msg = mMessages; msg != null; msg = msg.next) { 918 if (h == null || h == msg.target) { 919 pw.println(prefix + "Message " + n + ": " + msg.toString(now)); 920 } 921 n++; 922 } 923 pw.println(prefix + "(Total messages: " + n + ", polling=" + isPollingLocked() 924 + ", quitting=" + mQuitting + ")"); 925 } 926 } 927 writeToProto(ProtoOutputStream proto, long fieldId)928 void writeToProto(ProtoOutputStream proto, long fieldId) { 929 final long messageQueueToken = proto.start(fieldId); 930 synchronized (this) { 931 for (Message msg = mMessages; msg != null; msg = msg.next) { 932 msg.writeToProto(proto, MessageQueueProto.MESSAGES); 933 } 934 proto.write(MessageQueueProto.IS_POLLING_LOCKED, isPollingLocked()); 935 proto.write(MessageQueueProto.IS_QUITTING, mQuitting); 936 } 937 proto.end(messageQueueToken); 938 } 939 940 /** 941 * Callback interface for discovering when a thread is going to block 942 * waiting for more messages. 943 */ 944 public static interface IdleHandler { 945 /** 946 * Called when the message queue has run out of messages and will now 947 * wait for more. Return true to keep your idle handler active, false 948 * to have it removed. This may be called if there are still messages 949 * pending in the queue, but they are all scheduled to be dispatched 950 * after the current time. 951 */ queueIdle()952 boolean queueIdle(); 953 } 954 955 /** 956 * A listener which is invoked when file descriptor related events occur. 957 */ 958 public interface OnFileDescriptorEventListener { 959 /** 960 * File descriptor event: Indicates that the file descriptor is ready for input 961 * operations, such as reading. 962 * <p> 963 * The listener should read all available data from the file descriptor 964 * then return <code>true</code> to keep the listener active or <code>false</code> 965 * to remove the listener. 966 * </p><p> 967 * In the case of a socket, this event may be generated to indicate 968 * that there is at least one incoming connection that the listener 969 * should accept. 970 * </p><p> 971 * This event will only be generated if the {@link #EVENT_INPUT} event mask was 972 * specified when the listener was added. 973 * </p> 974 */ 975 public static final int EVENT_INPUT = 1 << 0; 976 977 /** 978 * File descriptor event: Indicates that the file descriptor is ready for output 979 * operations, such as writing. 980 * <p> 981 * The listener should write as much data as it needs. If it could not 982 * write everything at once, then it should return <code>true</code> to 983 * keep the listener active. Otherwise, it should return <code>false</code> 984 * to remove the listener then re-register it later when it needs to write 985 * something else. 986 * </p><p> 987 * This event will only be generated if the {@link #EVENT_OUTPUT} event mask was 988 * specified when the listener was added. 989 * </p> 990 */ 991 public static final int EVENT_OUTPUT = 1 << 1; 992 993 /** 994 * File descriptor event: Indicates that the file descriptor encountered a 995 * fatal error. 996 * <p> 997 * File descriptor errors can occur for various reasons. One common error 998 * is when the remote peer of a socket or pipe closes its end of the connection. 999 * </p><p> 1000 * This event may be generated at any time regardless of whether the 1001 * {@link #EVENT_ERROR} event mask was specified when the listener was added. 1002 * </p> 1003 */ 1004 public static final int EVENT_ERROR = 1 << 2; 1005 1006 /** @hide */ 1007 @Retention(RetentionPolicy.SOURCE) 1008 @IntDef(flag = true, prefix = { "EVENT_" }, value = { 1009 EVENT_INPUT, 1010 EVENT_OUTPUT, 1011 EVENT_ERROR 1012 }) 1013 public @interface Events {} 1014 1015 /** 1016 * Called when a file descriptor receives events. 1017 * 1018 * @param fd The file descriptor. 1019 * @param events The set of events that occurred: a combination of the 1020 * {@link #EVENT_INPUT}, {@link #EVENT_OUTPUT}, and {@link #EVENT_ERROR} event masks. 1021 * @return The new set of events to watch, or 0 to unregister the listener. 1022 * 1023 * @see #EVENT_INPUT 1024 * @see #EVENT_OUTPUT 1025 * @see #EVENT_ERROR 1026 */ onFileDescriptorEvents(@onNull FileDescriptor fd, @Events int events)1027 @Events int onFileDescriptorEvents(@NonNull FileDescriptor fd, @Events int events); 1028 } 1029 1030 private static final class FileDescriptorRecord { 1031 public final FileDescriptor mDescriptor; 1032 public int mEvents; 1033 public OnFileDescriptorEventListener mListener; 1034 public int mSeq; 1035 FileDescriptorRecord(FileDescriptor descriptor, int events, OnFileDescriptorEventListener listener)1036 public FileDescriptorRecord(FileDescriptor descriptor, 1037 int events, OnFileDescriptorEventListener listener) { 1038 mDescriptor = descriptor; 1039 mEvents = events; 1040 mListener = listener; 1041 } 1042 } 1043 } 1044