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 } 258 } 259 260 // Called from native code. dispatchEvents(int fd, int events)261 private int dispatchEvents(int fd, int events) { 262 // Get the file descriptor record and any state that might change. 263 final FileDescriptorRecord record; 264 final int oldWatchedEvents; 265 final OnFileDescriptorEventListener listener; 266 final int seq; 267 synchronized (this) { 268 record = mFileDescriptorRecords.get(fd); 269 if (record == null) { 270 return 0; // spurious, no listener registered 271 } 272 273 oldWatchedEvents = record.mEvents; 274 events &= oldWatchedEvents; // filter events based on current watched set 275 if (events == 0) { 276 return oldWatchedEvents; // spurious, watched events changed 277 } 278 279 listener = record.mListener; 280 seq = record.mSeq; 281 } 282 283 // Invoke the listener outside of the lock. 284 int newWatchedEvents = listener.onFileDescriptorEvents( 285 record.mDescriptor, events); 286 if (newWatchedEvents != 0) { 287 newWatchedEvents |= OnFileDescriptorEventListener.EVENT_ERROR; 288 } 289 290 // Update the file descriptor record if the listener changed the set of 291 // events to watch and the listener itself hasn't been updated since. 292 if (newWatchedEvents != oldWatchedEvents) { 293 synchronized (this) { 294 int index = mFileDescriptorRecords.indexOfKey(fd); 295 if (index >= 0 && mFileDescriptorRecords.valueAt(index) == record 296 && record.mSeq == seq) { 297 record.mEvents = newWatchedEvents; 298 if (newWatchedEvents == 0) { 299 mFileDescriptorRecords.removeAt(index); 300 } 301 } 302 } 303 } 304 305 // Return the new set of events to watch for native code to take care of. 306 return newWatchedEvents; 307 } 308 next()309 Message next() { 310 // Return here if the message loop has already quit and been disposed. 311 // This can happen if the application tries to restart a looper after quit 312 // which is not supported. 313 final long ptr = mPtr; 314 if (ptr == 0) { 315 return null; 316 } 317 318 int pendingIdleHandlerCount = -1; // -1 only during first iteration 319 int nextPollTimeoutMillis = 0; 320 for (;;) { 321 if (nextPollTimeoutMillis != 0) { 322 Binder.flushPendingCommands(); 323 } 324 325 nativePollOnce(ptr, nextPollTimeoutMillis); 326 327 synchronized (this) { 328 // Try to retrieve the next message. Return if found. 329 final long now = SystemClock.uptimeMillis(); 330 Message prevMsg = null; 331 Message msg = mMessages; 332 if (msg != null && msg.target == null) { 333 // Stalled by a barrier. Find the next asynchronous message in the queue. 334 do { 335 prevMsg = msg; 336 msg = msg.next; 337 } while (msg != null && !msg.isAsynchronous()); 338 } 339 if (msg != null) { 340 if (now < msg.when) { 341 // Next message is not ready. Set a timeout to wake up when it is ready. 342 nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE); 343 } else { 344 // Got a message. 345 mBlocked = false; 346 if (prevMsg != null) { 347 prevMsg.next = msg.next; 348 } else { 349 mMessages = msg.next; 350 } 351 msg.next = null; 352 if (DEBUG) Log.v(TAG, "Returning message: " + msg); 353 msg.markInUse(); 354 return msg; 355 } 356 } else { 357 // No more messages. 358 nextPollTimeoutMillis = -1; 359 } 360 361 // Process the quit message now that all pending messages have been handled. 362 if (mQuitting) { 363 dispose(); 364 return null; 365 } 366 367 // If first time idle, then get the number of idlers to run. 368 // Idle handles only run if the queue is empty or if the first message 369 // in the queue (possibly a barrier) is due to be handled in the future. 370 if (pendingIdleHandlerCount < 0 371 && (mMessages == null || now < mMessages.when)) { 372 pendingIdleHandlerCount = mIdleHandlers.size(); 373 } 374 if (pendingIdleHandlerCount <= 0) { 375 // No idle handlers to run. Loop and wait some more. 376 mBlocked = true; 377 continue; 378 } 379 380 if (mPendingIdleHandlers == null) { 381 mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)]; 382 } 383 mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers); 384 } 385 386 // Run the idle handlers. 387 // We only ever reach this code block during the first iteration. 388 for (int i = 0; i < pendingIdleHandlerCount; i++) { 389 final IdleHandler idler = mPendingIdleHandlers[i]; 390 mPendingIdleHandlers[i] = null; // release the reference to the handler 391 392 boolean keep = false; 393 try { 394 keep = idler.queueIdle(); 395 } catch (Throwable t) { 396 Log.wtf(TAG, "IdleHandler threw exception", t); 397 } 398 399 if (!keep) { 400 synchronized (this) { 401 mIdleHandlers.remove(idler); 402 } 403 } 404 } 405 406 // Reset the idle handler count to 0 so we do not run them again. 407 pendingIdleHandlerCount = 0; 408 409 // While calling an idle handler, a new message could have been delivered 410 // so go back and look again for a pending message without waiting. 411 nextPollTimeoutMillis = 0; 412 } 413 } 414 quit(boolean safe)415 void quit(boolean safe) { 416 if (!mQuitAllowed) { 417 throw new IllegalStateException("Main thread not allowed to quit."); 418 } 419 420 synchronized (this) { 421 if (mQuitting) { 422 return; 423 } 424 mQuitting = true; 425 426 if (safe) { 427 removeAllFutureMessagesLocked(); 428 } else { 429 removeAllMessagesLocked(); 430 } 431 432 // We can assume mPtr != 0 because mQuitting was previously false. 433 nativeWake(mPtr); 434 } 435 } 436 437 /** 438 * Posts a synchronization barrier to the Looper's message queue. 439 * 440 * Message processing occurs as usual until the message queue encounters the 441 * synchronization barrier that has been posted. When the barrier is encountered, 442 * later synchronous messages in the queue are stalled (prevented from being executed) 443 * until the barrier is released by calling {@link #removeSyncBarrier} and specifying 444 * the token that identifies the synchronization barrier. 445 * 446 * This method is used to immediately postpone execution of all subsequently posted 447 * synchronous messages until a condition is met that releases the barrier. 448 * Asynchronous messages (see {@link Message#isAsynchronous} are exempt from the barrier 449 * and continue to be processed as usual. 450 * 451 * This call must be always matched by a call to {@link #removeSyncBarrier} with 452 * the same token to ensure that the message queue resumes normal operation. 453 * Otherwise the application will probably hang! 454 * 455 * @return A token that uniquely identifies the barrier. This token must be 456 * passed to {@link #removeSyncBarrier} to release the barrier. 457 * 458 * @hide 459 */ postSyncBarrier()460 public int postSyncBarrier() { 461 return postSyncBarrier(SystemClock.uptimeMillis()); 462 } 463 postSyncBarrier(long when)464 private int postSyncBarrier(long when) { 465 // Enqueue a new sync barrier token. 466 // We don't need to wake the queue because the purpose of a barrier is to stall it. 467 synchronized (this) { 468 final int token = mNextBarrierToken++; 469 final Message msg = Message.obtain(); 470 msg.markInUse(); 471 msg.when = when; 472 msg.arg1 = token; 473 474 Message prev = null; 475 Message p = mMessages; 476 if (when != 0) { 477 while (p != null && p.when <= when) { 478 prev = p; 479 p = p.next; 480 } 481 } 482 if (prev != null) { // invariant: p == prev.next 483 msg.next = p; 484 prev.next = msg; 485 } else { 486 msg.next = p; 487 mMessages = msg; 488 } 489 return token; 490 } 491 } 492 493 /** 494 * Removes a synchronization barrier. 495 * 496 * @param token The synchronization barrier token that was returned by 497 * {@link #postSyncBarrier}. 498 * 499 * @throws IllegalStateException if the barrier was not found. 500 * 501 * @hide 502 */ removeSyncBarrier(int token)503 public void removeSyncBarrier(int token) { 504 // Remove a sync barrier token from the queue. 505 // If the queue is no longer stalled by a barrier then wake it. 506 synchronized (this) { 507 Message prev = null; 508 Message p = mMessages; 509 while (p != null && (p.target != null || p.arg1 != token)) { 510 prev = p; 511 p = p.next; 512 } 513 if (p == null) { 514 throw new IllegalStateException("The specified message queue synchronization " 515 + " barrier token has not been posted or has already been removed."); 516 } 517 final boolean needWake; 518 if (prev != null) { 519 prev.next = p.next; 520 needWake = false; 521 } else { 522 mMessages = p.next; 523 needWake = mMessages == null || mMessages.target != null; 524 } 525 p.recycleUnchecked(); 526 527 // If the loop is quitting then it is already awake. 528 // We can assume mPtr != 0 when mQuitting is false. 529 if (needWake && !mQuitting) { 530 nativeWake(mPtr); 531 } 532 } 533 } 534 enqueueMessage(Message msg, long when)535 boolean enqueueMessage(Message msg, long when) { 536 if (msg.target == null) { 537 throw new IllegalArgumentException("Message must have a target."); 538 } 539 if (msg.isInUse()) { 540 throw new IllegalStateException(msg + " This message is already in use."); 541 } 542 543 synchronized (this) { 544 if (mQuitting) { 545 IllegalStateException e = new IllegalStateException( 546 msg.target + " sending message to a Handler on a dead thread"); 547 Log.w(TAG, e.getMessage(), e); 548 msg.recycle(); 549 return false; 550 } 551 552 msg.markInUse(); 553 msg.when = when; 554 Message p = mMessages; 555 boolean needWake; 556 if (p == null || when == 0 || when < p.when) { 557 // New head, wake up the event queue if blocked. 558 msg.next = p; 559 mMessages = msg; 560 needWake = mBlocked; 561 } else { 562 // Inserted within the middle of the queue. Usually we don't have to wake 563 // up the event queue unless there is a barrier at the head of the queue 564 // and the message is the earliest asynchronous message in the queue. 565 needWake = mBlocked && p.target == null && msg.isAsynchronous(); 566 Message prev; 567 for (;;) { 568 prev = p; 569 p = p.next; 570 if (p == null || when < p.when) { 571 break; 572 } 573 if (needWake && p.isAsynchronous()) { 574 needWake = false; 575 } 576 } 577 msg.next = p; // invariant: p == prev.next 578 prev.next = msg; 579 } 580 581 // We can assume mPtr != 0 because mQuitting is false. 582 if (needWake) { 583 nativeWake(mPtr); 584 } 585 } 586 return true; 587 } 588 hasMessages(Handler h, int what, Object object)589 boolean hasMessages(Handler h, int what, Object object) { 590 if (h == null) { 591 return false; 592 } 593 594 synchronized (this) { 595 Message p = mMessages; 596 while (p != null) { 597 if (p.target == h && p.what == what && (object == null || p.obj == object)) { 598 return true; 599 } 600 p = p.next; 601 } 602 return false; 603 } 604 } 605 hasMessages(Handler h, Runnable r, Object object)606 boolean hasMessages(Handler h, Runnable r, Object object) { 607 if (h == null) { 608 return false; 609 } 610 611 synchronized (this) { 612 Message p = mMessages; 613 while (p != null) { 614 if (p.target == h && p.callback == r && (object == null || p.obj == object)) { 615 return true; 616 } 617 p = p.next; 618 } 619 return false; 620 } 621 } 622 hasMessages(Handler h)623 boolean hasMessages(Handler h) { 624 if (h == null) { 625 return false; 626 } 627 628 synchronized (this) { 629 Message p = mMessages; 630 while (p != null) { 631 if (p.target == h) { 632 return true; 633 } 634 p = p.next; 635 } 636 return false; 637 } 638 } 639 removeMessages(Handler h, int what, Object object)640 void removeMessages(Handler h, int what, Object object) { 641 if (h == null) { 642 return; 643 } 644 645 synchronized (this) { 646 Message p = mMessages; 647 648 // Remove all messages at front. 649 while (p != null && p.target == h && p.what == what 650 && (object == null || p.obj == object)) { 651 Message n = p.next; 652 mMessages = n; 653 p.recycleUnchecked(); 654 p = n; 655 } 656 657 // Remove all messages after front. 658 while (p != null) { 659 Message n = p.next; 660 if (n != null) { 661 if (n.target == h && n.what == what 662 && (object == null || n.obj == object)) { 663 Message nn = n.next; 664 n.recycleUnchecked(); 665 p.next = nn; 666 continue; 667 } 668 } 669 p = n; 670 } 671 } 672 } 673 removeMessages(Handler h, Runnable r, Object object)674 void removeMessages(Handler h, Runnable r, Object object) { 675 if (h == null || r == null) { 676 return; 677 } 678 679 synchronized (this) { 680 Message p = mMessages; 681 682 // Remove all messages at front. 683 while (p != null && p.target == h && p.callback == r 684 && (object == null || p.obj == object)) { 685 Message n = p.next; 686 mMessages = n; 687 p.recycleUnchecked(); 688 p = n; 689 } 690 691 // Remove all messages after front. 692 while (p != null) { 693 Message n = p.next; 694 if (n != null) { 695 if (n.target == h && n.callback == r 696 && (object == null || n.obj == object)) { 697 Message nn = n.next; 698 n.recycleUnchecked(); 699 p.next = nn; 700 continue; 701 } 702 } 703 p = n; 704 } 705 } 706 } 707 removeCallbacksAndMessages(Handler h, Object object)708 void removeCallbacksAndMessages(Handler h, Object object) { 709 if (h == null) { 710 return; 711 } 712 713 synchronized (this) { 714 Message p = mMessages; 715 716 // Remove all messages at front. 717 while (p != null && p.target == h 718 && (object == null || p.obj == object)) { 719 Message n = p.next; 720 mMessages = n; 721 p.recycleUnchecked(); 722 p = n; 723 } 724 725 // Remove all messages after front. 726 while (p != null) { 727 Message n = p.next; 728 if (n != null) { 729 if (n.target == h && (object == null || n.obj == object)) { 730 Message nn = n.next; 731 n.recycleUnchecked(); 732 p.next = nn; 733 continue; 734 } 735 } 736 p = n; 737 } 738 } 739 } 740 removeAllMessagesLocked()741 private void removeAllMessagesLocked() { 742 Message p = mMessages; 743 while (p != null) { 744 Message n = p.next; 745 p.recycleUnchecked(); 746 p = n; 747 } 748 mMessages = null; 749 } 750 removeAllFutureMessagesLocked()751 private void removeAllFutureMessagesLocked() { 752 final long now = SystemClock.uptimeMillis(); 753 Message p = mMessages; 754 if (p != null) { 755 if (p.when > now) { 756 removeAllMessagesLocked(); 757 } else { 758 Message n; 759 for (;;) { 760 n = p.next; 761 if (n == null) { 762 return; 763 } 764 if (n.when > now) { 765 break; 766 } 767 p = n; 768 } 769 p.next = null; 770 do { 771 p = n; 772 n = p.next; 773 p.recycleUnchecked(); 774 } while (n != null); 775 } 776 } 777 } 778 dump(Printer pw, String prefix, Handler h)779 void dump(Printer pw, String prefix, Handler h) { 780 synchronized (this) { 781 long now = SystemClock.uptimeMillis(); 782 int n = 0; 783 for (Message msg = mMessages; msg != null; msg = msg.next) { 784 if (h == null || h == msg.target) { 785 pw.println(prefix + "Message " + n + ": " + msg.toString(now)); 786 } 787 n++; 788 } 789 pw.println(prefix + "(Total messages: " + n + ", polling=" + isPollingLocked() 790 + ", quitting=" + mQuitting + ")"); 791 } 792 } 793 writeToProto(ProtoOutputStream proto, long fieldId)794 void writeToProto(ProtoOutputStream proto, long fieldId) { 795 final long messageQueueToken = proto.start(fieldId); 796 synchronized (this) { 797 for (Message msg = mMessages; msg != null; msg = msg.next) { 798 msg.writeToProto(proto, MessageQueueProto.MESSAGES); 799 } 800 proto.write(MessageQueueProto.IS_POLLING_LOCKED, isPollingLocked()); 801 proto.write(MessageQueueProto.IS_QUITTING, mQuitting); 802 } 803 proto.end(messageQueueToken); 804 } 805 806 /** 807 * Callback interface for discovering when a thread is going to block 808 * waiting for more messages. 809 */ 810 public static interface IdleHandler { 811 /** 812 * Called when the message queue has run out of messages and will now 813 * wait for more. Return true to keep your idle handler active, false 814 * to have it removed. This may be called if there are still messages 815 * pending in the queue, but they are all scheduled to be dispatched 816 * after the current time. 817 */ queueIdle()818 boolean queueIdle(); 819 } 820 821 /** 822 * A listener which is invoked when file descriptor related events occur. 823 */ 824 public interface OnFileDescriptorEventListener { 825 /** 826 * File descriptor event: Indicates that the file descriptor is ready for input 827 * operations, such as reading. 828 * <p> 829 * The listener should read all available data from the file descriptor 830 * then return <code>true</code> to keep the listener active or <code>false</code> 831 * to remove the listener. 832 * </p><p> 833 * In the case of a socket, this event may be generated to indicate 834 * that there is at least one incoming connection that the listener 835 * should accept. 836 * </p><p> 837 * This event will only be generated if the {@link #EVENT_INPUT} event mask was 838 * specified when the listener was added. 839 * </p> 840 */ 841 public static final int EVENT_INPUT = 1 << 0; 842 843 /** 844 * File descriptor event: Indicates that the file descriptor is ready for output 845 * operations, such as writing. 846 * <p> 847 * The listener should write as much data as it needs. If it could not 848 * write everything at once, then it should return <code>true</code> to 849 * keep the listener active. Otherwise, it should return <code>false</code> 850 * to remove the listener then re-register it later when it needs to write 851 * something else. 852 * </p><p> 853 * This event will only be generated if the {@link #EVENT_OUTPUT} event mask was 854 * specified when the listener was added. 855 * </p> 856 */ 857 public static final int EVENT_OUTPUT = 1 << 1; 858 859 /** 860 * File descriptor event: Indicates that the file descriptor encountered a 861 * fatal error. 862 * <p> 863 * File descriptor errors can occur for various reasons. One common error 864 * is when the remote peer of a socket or pipe closes its end of the connection. 865 * </p><p> 866 * This event may be generated at any time regardless of whether the 867 * {@link #EVENT_ERROR} event mask was specified when the listener was added. 868 * </p> 869 */ 870 public static final int EVENT_ERROR = 1 << 2; 871 872 /** @hide */ 873 @Retention(RetentionPolicy.SOURCE) 874 @IntDef(flag=true, value={EVENT_INPUT, EVENT_OUTPUT, EVENT_ERROR}) 875 public @interface Events {} 876 877 /** 878 * Called when a file descriptor receives events. 879 * 880 * @param fd The file descriptor. 881 * @param events The set of events that occurred: a combination of the 882 * {@link #EVENT_INPUT}, {@link #EVENT_OUTPUT}, and {@link #EVENT_ERROR} event masks. 883 * @return The new set of events to watch, or 0 to unregister the listener. 884 * 885 * @see #EVENT_INPUT 886 * @see #EVENT_OUTPUT 887 * @see #EVENT_ERROR 888 */ onFileDescriptorEvents(@onNull FileDescriptor fd, @Events int events)889 @Events int onFileDescriptorEvents(@NonNull FileDescriptor fd, @Events int events); 890 } 891 892 private static final class FileDescriptorRecord { 893 public final FileDescriptor mDescriptor; 894 public int mEvents; 895 public OnFileDescriptorEventListener mListener; 896 public int mSeq; 897 FileDescriptorRecord(FileDescriptor descriptor, int events, OnFileDescriptorEventListener listener)898 public FileDescriptorRecord(FileDescriptor descriptor, 899 int events, OnFileDescriptorEventListener listener) { 900 mDescriptor = descriptor; 901 mEvents = events; 902 mListener = listener; 903 } 904 } 905 } 906