blob: 96e7a598ab73bf2fe82852e6fd049a5cf6370c91 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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
17package android.os;
18
Jeff Browndc3eb4b2015-03-05 18:21:06 -080019import android.annotation.IntDef;
20import android.annotation.NonNull;
Netta P958d0a52017-02-07 11:20:55 -080021import android.os.MessageQueueProto;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080022import android.util.Log;
Jeff Brown5182c782013-10-15 20:31:52 -070023import android.util.Printer;
Jeff Browndc3eb4b2015-03-05 18:21:06 -080024import android.util.SparseArray;
Netta P958d0a52017-02-07 11:20:55 -080025import android.util.proto.ProtoOutputStream;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080026
Jeff Browndc3eb4b2015-03-05 18:21:06 -080027import java.io.FileDescriptor;
28import java.lang.annotation.Retention;
29import java.lang.annotation.RetentionPolicy;
Jeff Brown46b9ac02010-04-22 18:58:52 -070030import java.util.ArrayList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080031
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.
Netta P958d0a52017-02-07 11:20:55 -080036 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037 * <p>You can retrieve the MessageQueue for the current thread with
38 * {@link Looper#myQueue() Looper.myQueue()}.
39 */
Jeff Brown67fc67c2013-04-01 13:00:33 -070040public final class MessageQueue {
Jeff Browndc3eb4b2015-03-05 18:21:06 -080041 private static final String TAG = "MessageQueue";
42 private static final boolean DEBUG = false;
43
Jeff Brown0f85ce32012-02-16 14:41:10 -080044 // True if the message queue can be quit.
45 private final boolean mQuitAllowed;
46
47 @SuppressWarnings("unused")
Ashok Bhat63a37152014-01-10 14:15:21 +000048 private long mPtr; // used by native code
Jeff Brown0f85ce32012-02-16 14:41:10 -080049
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080050 Message mMessages;
Jeff Brown46b9ac02010-04-22 18:58:52 -070051 private final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<IdleHandler>();
Jeff Browndc3eb4b2015-03-05 18:21:06 -080052 private SparseArray<FileDescriptorRecord> mFileDescriptorRecords;
Jeff Browned739322010-09-21 15:14:14 -070053 private IdleHandler[] mPendingIdleHandlers;
Jeff Brown013cf842013-09-06 16:24:36 -070054 private boolean mQuitting;
Christopher Tatefa9e7c02010-05-06 12:07:10 -070055
Jeff Brown415d8c32010-10-05 15:35:37 -070056 // Indicates whether next() is blocked waiting in pollOnce() with a non-zero timeout.
57 private boolean mBlocked;
58
Jeff Brown0f85ce32012-02-16 14:41:10 -080059 // The next barrier token.
60 // Barriers are indicated by messages with a null target whose arg1 field carries the token.
61 private int mNextBarrierToken;
Jeff Browne799cb72012-02-14 11:53:33 -080062
Ashok Bhat63a37152014-01-10 14:15:21 +000063 private native static long nativeInit();
64 private native static void nativeDestroy(long ptr);
Jeff Browndc3eb4b2015-03-05 18:21:06 -080065 private native void nativePollOnce(long ptr, int timeoutMillis); /*non-static for callbacks*/
Ashok Bhat63a37152014-01-10 14:15:21 +000066 private native static void nativeWake(long ptr);
Jeff Brown6c7b41a2015-02-26 14:43:53 -080067 private native static boolean nativeIsPolling(long ptr);
Jeff Browndc3eb4b2015-03-05 18:21:06 -080068 private native static void nativeSetFileDescriptorEvents(long ptr, int fd, int events);
Jeff Browne799cb72012-02-14 11:53:33 -080069
Jeff Brown0f85ce32012-02-16 14:41:10 -080070 MessageQueue(boolean quitAllowed) {
71 mQuitAllowed = quitAllowed;
Jeff Brown864693462013-01-28 14:25:53 -080072 mPtr = nativeInit();
Christopher Tatefa9e7c02010-05-06 12:07:10 -070073 }
Jeff Brown0f85ce32012-02-16 14:41:10 -080074
Jeff Brown46b9ac02010-04-22 18:58:52 -070075 @Override
76 protected void finalize() throws Throwable {
77 try {
Jeff Brown864693462013-01-28 14:25:53 -080078 dispose();
Jeff Brown46b9ac02010-04-22 18:58:52 -070079 } finally {
80 super.finalize();
81 }
82 }
Christopher Tatefa9e7c02010-05-06 12:07:10 -070083
Jeff Brown013cf842013-09-06 16:24:36 -070084 // Disposes of the underlying message queue.
85 // Must only be called on the looper thread or the finalizer.
Jeff Brown864693462013-01-28 14:25:53 -080086 private void dispose() {
87 if (mPtr != 0) {
88 nativeDestroy(mPtr);
89 mPtr = 0;
90 }
91 }
92
Jeff Brown6c7b41a2015-02-26 14:43:53 -080093 /**
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 */
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 */
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800117 public void addIdleHandler(@NonNull IdleHandler handler) {
Jeff Brown6c7b41a2015-02-26 14:43:53 -0800118 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 */
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800135 public void removeIdleHandler(@NonNull IdleHandler handler) {
Jeff Brown6c7b41a2015-02-26 14:43:53 -0800136 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 */
152 public boolean isPolling() {
153 synchronized (this) {
154 return isPollingLocked();
155 }
156 }
157
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
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800164 /**
Jeff Brown3f640522015-05-15 12:26:15 -0700165 * Adds a file descriptor listener to receive notification when file descriptor
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800166 * related events occur.
167 * <p>
168 * If the file descriptor has already been registered, the specified events
Jeff Brown3f640522015-05-15 12:26:15 -0700169 * 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.
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800171 * </p><p>
Jeff Brown3f640522015-05-15 12:26:15 -0700172 * It is important to always unregister the listener when the file descriptor
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800173 * is no longer of use.
174 * </p>
175 *
Jeff Brown3f640522015-05-15 12:26:15 -0700176 * @param fd The file descriptor for which a listener will be registered.
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800177 * @param events The set of events to receive: a combination of the
Jeff Brown3f640522015-05-15 12:26:15 -0700178 * {@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.
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800183 *
Jeff Brown3f640522015-05-15 12:26:15 -0700184 * @see OnFileDescriptorEventListener
185 * @see #removeOnFileDescriptorEventListener
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800186 */
Jeff Brown3f640522015-05-15 12:26:15 -0700187 public void addOnFileDescriptorEventListener(@NonNull FileDescriptor fd,
188 @OnFileDescriptorEventListener.Events int events,
189 @NonNull OnFileDescriptorEventListener listener) {
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800190 if (fd == null) {
191 throw new IllegalArgumentException("fd must not be null");
192 }
Jeff Brown3f640522015-05-15 12:26:15 -0700193 if (listener == null) {
194 throw new IllegalArgumentException("listener must not be null");
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800195 }
196
197 synchronized (this) {
Jeff Brown3f640522015-05-15 12:26:15 -0700198 updateOnFileDescriptorEventListenerLocked(fd, events, listener);
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800199 }
200 }
201
202 /**
Jeff Brown3f640522015-05-15 12:26:15 -0700203 * Removes a file descriptor listener.
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800204 * <p>
Jeff Brown3f640522015-05-15 12:26:15 -0700205 * This method does nothing if no listener has been registered for the
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800206 * specified file descriptor.
207 * </p>
208 *
Jeff Brown3f640522015-05-15 12:26:15 -0700209 * @param fd The file descriptor whose listener will be unregistered.
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800210 *
Jeff Brown3f640522015-05-15 12:26:15 -0700211 * @see OnFileDescriptorEventListener
212 * @see #addOnFileDescriptorEventListener
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800213 */
Jeff Brown3f640522015-05-15 12:26:15 -0700214 public void removeOnFileDescriptorEventListener(@NonNull FileDescriptor fd) {
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800215 if (fd == null) {
216 throw new IllegalArgumentException("fd must not be null");
217 }
218
219 synchronized (this) {
Jeff Brown3f640522015-05-15 12:26:15 -0700220 updateOnFileDescriptorEventListenerLocked(fd, 0, null);
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800221 }
222 }
223
Jeff Brown3f640522015-05-15 12:26:15 -0700224 private void updateOnFileDescriptorEventListenerLocked(FileDescriptor fd, int events,
225 OnFileDescriptorEventListener listener) {
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800226 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) {
Jeff Brown3f640522015-05-15 12:26:15 -0700241 events |= OnFileDescriptorEventListener.EVENT_ERROR;
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800242 if (record == null) {
243 if (mFileDescriptorRecords == null) {
244 mFileDescriptorRecords = new SparseArray<FileDescriptorRecord>();
245 }
Jeff Brown3f640522015-05-15 12:26:15 -0700246 record = new FileDescriptorRecord(fd, events, listener);
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800247 mFileDescriptorRecords.put(fdNum, record);
248 } else {
Jeff Brown3f640522015-05-15 12:26:15 -0700249 record.mListener = listener;
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800250 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.
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;
Jeff Brown3f640522015-05-15 12:26:15 -0700265 final OnFileDescriptorEventListener listener;
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800266 final int seq;
267 synchronized (this) {
268 record = mFileDescriptorRecords.get(fd);
269 if (record == null) {
Jeff Brown3f640522015-05-15 12:26:15 -0700270 return 0; // spurious, no listener registered
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800271 }
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
Jeff Brown3f640522015-05-15 12:26:15 -0700279 listener = record.mListener;
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800280 seq = record.mSeq;
281 }
282
Jeff Brown3f640522015-05-15 12:26:15 -0700283 // Invoke the listener outside of the lock.
284 int newWatchedEvents = listener.onFileDescriptorEvents(
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800285 record.mDescriptor, events);
286 if (newWatchedEvents != 0) {
Jeff Brown3f640522015-05-15 12:26:15 -0700287 newWatchedEvents |= OnFileDescriptorEventListener.EVENT_ERROR;
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800288 }
289
Jeff Brown3f640522015-05-15 12:26:15 -0700290 // 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.
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800292 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
Jeff Brown67fc67c2013-04-01 13:00:33 -0700309 Message next() {
Jeff Brown60583902013-09-09 16:14:20 -0700310 // 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.
Narayan Kamathab864342014-01-16 11:22:52 +0000313 final long ptr = mPtr;
Jeff Brown60583902013-09-09 16:14:20 -0700314 if (ptr == 0) {
315 return null;
316 }
317
Jeff Browned739322010-09-21 15:14:14 -0700318 int pendingIdleHandlerCount = -1; // -1 only during first iteration
319 int nextPollTimeoutMillis = 0;
Jeff Browned739322010-09-21 15:14:14 -0700320 for (;;) {
321 if (nextPollTimeoutMillis != 0) {
322 Binder.flushPendingCommands();
323 }
Jeff Brown013cf842013-09-06 16:24:36 -0700324
Jeff Brown60583902013-09-09 16:14:20 -0700325 nativePollOnce(ptr, nextPollTimeoutMillis);
Christopher Tatefa9e7c02010-05-06 12:07:10 -0700326
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800327 synchronized (this) {
Jeff Browned739322010-09-21 15:14:14 -0700328 // Try to retrieve the next message. Return if found.
329 final long now = SystemClock.uptimeMillis();
Jeff Browne799cb72012-02-14 11:53:33 -0800330 Message prevMsg = null;
331 Message msg = mMessages;
Jeff Brown0f85ce32012-02-16 14:41:10 -0800332 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) {
Jeff Browne799cb72012-02-14 11:53:33 -0800341 // Next message is not ready. Set a timeout to wake up when it is ready.
Jeff Brown0f85ce32012-02-16 14:41:10 -0800342 nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
343 } else {
Jeff Browne799cb72012-02-14 11:53:33 -0800344 // Got a message.
Jeff Brown415d8c32010-10-05 15:35:37 -0700345 mBlocked = false;
Jeff Browne799cb72012-02-14 11:53:33 -0800346 if (prevMsg != null) {
347 prevMsg.next = msg.next;
348 } else {
349 mMessages = msg.next;
350 }
Jeff Brown415d8c32010-10-05 15:35:37 -0700351 msg.next = null;
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800352 if (DEBUG) Log.v(TAG, "Returning message: " + msg);
353 msg.markInUse();
Jeff Browned739322010-09-21 15:14:14 -0700354 return msg;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800355 }
Jeff Brown0f85ce32012-02-16 14:41:10 -0800356 } else {
357 // No more messages.
358 nextPollTimeoutMillis = -1;
Jeff Browned739322010-09-21 15:14:14 -0700359 }
360
Jeff Brown024136f2013-04-11 19:21:32 -0700361 // Process the quit message now that all pending messages have been handled.
Jeff Brown013cf842013-09-06 16:24:36 -0700362 if (mQuitting) {
Jeff Brown024136f2013-04-11 19:21:32 -0700363 dispose();
364 return null;
365 }
366
Jeff Browne799cb72012-02-14 11:53:33 -0800367 // If first time idle, then get the number of idlers to run.
Jeff Brown0f85ce32012-02-16 14:41:10 -0800368 // 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)) {
Jeff Browned739322010-09-21 15:14:14 -0700372 pendingIdleHandlerCount = mIdleHandlers.size();
373 }
Jeff Browne799cb72012-02-14 11:53:33 -0800374 if (pendingIdleHandlerCount <= 0) {
Jeff Browned739322010-09-21 15:14:14 -0700375 // No idle handlers to run. Loop and wait some more.
Jeff Brown415d8c32010-10-05 15:35:37 -0700376 mBlocked = true;
Jeff Browned739322010-09-21 15:14:14 -0700377 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) {
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800396 Log.wtf(TAG, "IdleHandler threw exception", t);
Jeff Browned739322010-09-21 15:14:14 -0700397 }
398
399 if (!keep) {
400 synchronized (this) {
401 mIdleHandlers.remove(idler);
402 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800403 }
404 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800405
Jeff Browned739322010-09-21 15:14:14 -0700406 // Reset the idle handler count to 0 so we do not run them again.
407 pendingIdleHandlerCount = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800408
Jeff Browned739322010-09-21 15:14:14 -0700409 // 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 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800413 }
414
Jeff Brown8b60e452013-04-18 15:17:48 -0700415 void quit(boolean safe) {
Jeff Brown0f85ce32012-02-16 14:41:10 -0800416 if (!mQuitAllowed) {
Jeff Brown9867ed72014-02-28 14:00:57 -0800417 throw new IllegalStateException("Main thread not allowed to quit.");
Jeff Brown0f85ce32012-02-16 14:41:10 -0800418 }
419
420 synchronized (this) {
Jeff Brown013cf842013-09-06 16:24:36 -0700421 if (mQuitting) {
Jeff Brown0f85ce32012-02-16 14:41:10 -0800422 return;
423 }
Jeff Brown013cf842013-09-06 16:24:36 -0700424 mQuitting = true;
Jeff Brown8b60e452013-04-18 15:17:48 -0700425
426 if (safe) {
427 removeAllFutureMessagesLocked();
428 } else {
429 removeAllMessagesLocked();
430 }
Jeff Brown013cf842013-09-06 16:24:36 -0700431
432 // We can assume mPtr != 0 because mQuitting was previously false.
433 nativeWake(mPtr);
Jeff Brown0f85ce32012-02-16 14:41:10 -0800434 }
Jeff Brown0f85ce32012-02-16 14:41:10 -0800435 }
436
Jeff Brown3d4e7efe2015-02-26 15:34:16 -0800437 /**
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 */
460 public int postSyncBarrier() {
461 return postSyncBarrier(SystemClock.uptimeMillis());
462 }
463
464 private int postSyncBarrier(long when) {
Jeff Brown0f85ce32012-02-16 14:41:10 -0800465 // 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();
Jeff Brown9867ed72014-02-28 14:00:57 -0800470 msg.markInUse();
Jeff Brown5182c782013-10-15 20:31:52 -0700471 msg.when = when;
Jeff Brown0f85ce32012-02-16 14:41:10 -0800472 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
Jeff Brown3d4e7efe2015-02-26 15:34:16 -0800493 /**
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 */
503 public void removeSyncBarrier(int token) {
Jeff Brown0f85ce32012-02-16 14:41:10 -0800504 // Remove a sync barrier token from the queue.
505 // If the queue is no longer stalled by a barrier then wake it.
Jeff Brown0f85ce32012-02-16 14:41:10 -0800506 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 }
Jeff Brown013cf842013-09-06 16:24:36 -0700517 final boolean needWake;
Jeff Brown0f85ce32012-02-16 14:41:10 -0800518 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 }
Jeff Brown9867ed72014-02-28 14:00:57 -0800525 p.recycleUnchecked();
Jeff Brown013cf842013-09-06 16:24:36 -0700526
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 }
Jeff Brown0f85ce32012-02-16 14:41:10 -0800532 }
533 }
534
Jeff Brown67fc67c2013-04-01 13:00:33 -0700535 boolean enqueueMessage(Message msg, long when) {
Jeff Brown0f85ce32012-02-16 14:41:10 -0800536 if (msg.target == null) {
Jeff Brown9867ed72014-02-28 14:00:57 -0800537 throw new IllegalArgumentException("Message must have a target.");
538 }
539 if (msg.isInUse()) {
540 throw new IllegalStateException(msg + " This message is already in use.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800541 }
Jeff Brown0f85ce32012-02-16 14:41:10 -0800542
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800543 synchronized (this) {
Jeff Brown013cf842013-09-06 16:24:36 -0700544 if (mQuitting) {
Jeff Brown9867ed72014-02-28 14:00:57 -0800545 IllegalStateException e = new IllegalStateException(
Jeff Brown0f85ce32012-02-16 14:41:10 -0800546 msg.target + " sending message to a Handler on a dead thread");
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800547 Log.w(TAG, e.getMessage(), e);
Jeff Brown9867ed72014-02-28 14:00:57 -0800548 msg.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800549 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800550 }
551
Jeff Brown9867ed72014-02-28 14:00:57 -0800552 msg.markInUse();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800553 msg.when = when;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800554 Message p = mMessages;
Jeff Brown013cf842013-09-06 16:24:36 -0700555 boolean needWake;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800556 if (p == null || when == 0 || when < p.when) {
Jeff Browne799cb72012-02-14 11:53:33 -0800557 // New head, wake up the event queue if blocked.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800558 msg.next = p;
559 mMessages = msg;
Jeff Browne799cb72012-02-14 11:53:33 -0800560 needWake = mBlocked;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800561 } else {
Jeff Browne799cb72012-02-14 11:53:33 -0800562 // Inserted within the middle of the queue. Usually we don't have to wake
Jeff Brown0f85ce32012-02-16 14:41:10 -0800563 // 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 (;;) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800568 prev = p;
569 p = p.next;
Jeff Brown0f85ce32012-02-16 14:41:10 -0800570 if (p == null || when < p.when) {
571 break;
572 }
573 if (needWake && p.isAsynchronous()) {
574 needWake = false;
575 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800576 }
Jeff Brown0f85ce32012-02-16 14:41:10 -0800577 msg.next = p; // invariant: p == prev.next
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800578 prev.next = msg;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800579 }
Jeff Brown013cf842013-09-06 16:24:36 -0700580
581 // We can assume mPtr != 0 because mQuitting is false.
582 if (needWake) {
583 nativeWake(mPtr);
584 }
Jeff Brown415d8c32010-10-05 15:35:37 -0700585 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800586 return true;
587 }
588
Jeff Brown67fc67c2013-04-01 13:00:33 -0700589 boolean hasMessages(Handler h, int what, Object object) {
Jeff Brown0f85ce32012-02-16 14:41:10 -0800590 if (h == null) {
591 return false;
592 }
593
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800594 synchronized (this) {
595 Message p = mMessages;
Jeff Brown0f85ce32012-02-16 14:41:10 -0800596 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
Jeff Brown67fc67c2013-04-01 13:00:33 -0700606 boolean hasMessages(Handler h, Runnable r, Object object) {
Romain Guyba6be8a2012-04-23 18:22:09 -0700607 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
Dianne Hackborncb015632017-06-14 17:30:15 -0700623 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
Jeff Brown67fc67c2013-04-01 13:00:33 -0700640 void removeMessages(Handler h, int what, Object object) {
Jeff Brown0f85ce32012-02-16 14:41:10 -0800641 if (h == null) {
642 return;
643 }
644
645 synchronized (this) {
646 Message p = mMessages;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800647
648 // Remove all messages at front.
649 while (p != null && p.target == h && p.what == what
650 && (object == null || p.obj == object)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800651 Message n = p.next;
652 mMessages = n;
Jeff Brown9867ed72014-02-28 14:00:57 -0800653 p.recycleUnchecked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800654 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)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800663 Message nn = n.next;
Jeff Brown9867ed72014-02-28 14:00:57 -0800664 n.recycleUnchecked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800665 p.next = nn;
666 continue;
667 }
668 }
669 p = n;
670 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800671 }
672 }
673
Jeff Brown67fc67c2013-04-01 13:00:33 -0700674 void removeMessages(Handler h, Runnable r, Object object) {
Jeff Brown0f85ce32012-02-16 14:41:10 -0800675 if (h == null || r == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800676 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;
Jeff Brown9867ed72014-02-28 14:00:57 -0800687 p.recycleUnchecked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800688 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;
Jeff Brown9867ed72014-02-28 14:00:57 -0800698 n.recycleUnchecked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800699 p.next = nn;
700 continue;
701 }
702 }
703 p = n;
704 }
705 }
706 }
707
Jeff Brown67fc67c2013-04-01 13:00:33 -0700708 void removeCallbacksAndMessages(Handler h, Object object) {
Jeff Brown0f85ce32012-02-16 14:41:10 -0800709 if (h == null) {
710 return;
711 }
712
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800713 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;
Jeff Brown9867ed72014-02-28 14:00:57 -0800721 p.recycleUnchecked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800722 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;
Jeff Brown9867ed72014-02-28 14:00:57 -0800731 n.recycleUnchecked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800732 p.next = nn;
733 continue;
734 }
735 }
736 p = n;
737 }
738 }
739 }
Jeff Brown8b60e452013-04-18 15:17:48 -0700740
741 private void removeAllMessagesLocked() {
742 Message p = mMessages;
743 while (p != null) {
744 Message n = p.next;
Jeff Brown9867ed72014-02-28 14:00:57 -0800745 p.recycleUnchecked();
Jeff Brown8b60e452013-04-18 15:17:48 -0700746 p = n;
747 }
748 mMessages = null;
749 }
750
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;
Jeff Brown9867ed72014-02-28 14:00:57 -0800773 p.recycleUnchecked();
Jeff Brown8b60e452013-04-18 15:17:48 -0700774 } while (n != null);
775 }
776 }
777 }
Jeff Brown5182c782013-10-15 20:31:52 -0700778
Dianne Hackborncb015632017-06-14 17:30:15 -0700779 void dump(Printer pw, String prefix, Handler h) {
Jeff Brown5182c782013-10-15 20:31:52 -0700780 synchronized (this) {
781 long now = SystemClock.uptimeMillis();
782 int n = 0;
783 for (Message msg = mMessages; msg != null; msg = msg.next) {
Dianne Hackborncb015632017-06-14 17:30:15 -0700784 if (h == null || h == msg.target) {
785 pw.println(prefix + "Message " + n + ": " + msg.toString(now));
786 }
Jeff Brown5182c782013-10-15 20:31:52 -0700787 n++;
788 }
Jeff Brown6c7b41a2015-02-26 14:43:53 -0800789 pw.println(prefix + "(Total messages: " + n + ", polling=" + isPollingLocked()
Jeff Brown5182c782013-10-15 20:31:52 -0700790 + ", quitting=" + mQuitting + ")");
791 }
792 }
Jeff Brown6c7b41a2015-02-26 14:43:53 -0800793
Netta P958d0a52017-02-07 11:20:55 -0800794 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
Jeff Brown6c7b41a2015-02-26 14:43:53 -0800806 /**
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 */
818 boolean queueIdle();
819 }
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800820
821 /**
Jeff Brown3f640522015-05-15 12:26:15 -0700822 * A listener which is invoked when file descriptor related events occur.
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800823 */
Jeff Brown3f640522015-05-15 12:26:15 -0700824 public interface OnFileDescriptorEventListener {
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800825 /**
826 * File descriptor event: Indicates that the file descriptor is ready for input
827 * operations, such as reading.
828 * <p>
Jeff Brown3f640522015-05-15 12:26:15 -0700829 * 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.
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800832 * </p><p>
833 * In the case of a socket, this event may be generated to indicate
Jeff Brown3f640522015-05-15 12:26:15 -0700834 * that there is at least one incoming connection that the listener
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800835 * should accept.
836 * </p><p>
837 * This event will only be generated if the {@link #EVENT_INPUT} event mask was
Jeff Brown3f640522015-05-15 12:26:15 -0700838 * specified when the listener was added.
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800839 * </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>
Jeff Brown3f640522015-05-15 12:26:15 -0700847 * The listener should write as much data as it needs. If it could not
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800848 * write everything at once, then it should return <code>true</code> to
Jeff Brown3f640522015-05-15 12:26:15 -0700849 * 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
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800851 * something else.
852 * </p><p>
853 * This event will only be generated if the {@link #EVENT_OUTPUT} event mask was
Jeff Brown3f640522015-05-15 12:26:15 -0700854 * specified when the listener was added.
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800855 * </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
Jeff Brown3f640522015-05-15 12:26:15 -0700867 * {@link #EVENT_ERROR} event mask was specified when the listener was added.
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800868 * </p>
869 */
870 public static final int EVENT_ERROR = 1 << 2;
871
872 /** @hide */
873 @Retention(RetentionPolicy.SOURCE)
Jeff Sharkeyce8db992017-12-13 20:05:05 -0700874 @IntDef(flag = true, prefix = { "EVENT_" }, value = {
875 EVENT_INPUT,
876 EVENT_OUTPUT,
877 EVENT_ERROR
878 })
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800879 public @interface Events {}
880
881 /**
882 * Called when a file descriptor receives events.
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800883 *
884 * @param fd The file descriptor.
885 * @param events The set of events that occurred: a combination of the
886 * {@link #EVENT_INPUT}, {@link #EVENT_OUTPUT}, and {@link #EVENT_ERROR} event masks.
Jeff Brown3f640522015-05-15 12:26:15 -0700887 * @return The new set of events to watch, or 0 to unregister the listener.
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800888 *
889 * @see #EVENT_INPUT
890 * @see #EVENT_OUTPUT
891 * @see #EVENT_ERROR
892 */
Jeff Brown3f640522015-05-15 12:26:15 -0700893 @Events int onFileDescriptorEvents(@NonNull FileDescriptor fd, @Events int events);
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800894 }
895
896 private static final class FileDescriptorRecord {
897 public final FileDescriptor mDescriptor;
898 public int mEvents;
Jeff Brown3f640522015-05-15 12:26:15 -0700899 public OnFileDescriptorEventListener mListener;
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800900 public int mSeq;
901
902 public FileDescriptorRecord(FileDescriptor descriptor,
Jeff Brown3f640522015-05-15 12:26:15 -0700903 int events, OnFileDescriptorEventListener listener) {
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800904 mDescriptor = descriptor;
905 mEvents = events;
Jeff Brown3f640522015-05-15 12:26:15 -0700906 mListener = listener;
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800907 }
908 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800909}