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