blob: b1c33c2dac00dbc8c8f219f7eb5ee940b5e28e30 [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);
David Pursellc16b7752017-08-07 16:32:36 -0700257 nativeSetFileDescriptorEvents(mPtr, fdNum, 0);
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800258 }
259 }
260
261 // Called from native code.
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;
Jeff Brown3f640522015-05-15 12:26:15 -0700266 final OnFileDescriptorEventListener listener;
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800267 final int seq;
268 synchronized (this) {
269 record = mFileDescriptorRecords.get(fd);
270 if (record == null) {
Jeff Brown3f640522015-05-15 12:26:15 -0700271 return 0; // spurious, no listener registered
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800272 }
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
Jeff Brown3f640522015-05-15 12:26:15 -0700280 listener = record.mListener;
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800281 seq = record.mSeq;
282 }
283
Jeff Brown3f640522015-05-15 12:26:15 -0700284 // Invoke the listener outside of the lock.
285 int newWatchedEvents = listener.onFileDescriptorEvents(
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800286 record.mDescriptor, events);
287 if (newWatchedEvents != 0) {
Jeff Brown3f640522015-05-15 12:26:15 -0700288 newWatchedEvents |= OnFileDescriptorEventListener.EVENT_ERROR;
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800289 }
290
Jeff Brown3f640522015-05-15 12:26:15 -0700291 // 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.
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800293 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
Jeff Brown67fc67c2013-04-01 13:00:33 -0700310 Message next() {
Jeff Brown60583902013-09-09 16:14:20 -0700311 // 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.
Narayan Kamathab864342014-01-16 11:22:52 +0000314 final long ptr = mPtr;
Jeff Brown60583902013-09-09 16:14:20 -0700315 if (ptr == 0) {
316 return null;
317 }
318
Jeff Browned739322010-09-21 15:14:14 -0700319 int pendingIdleHandlerCount = -1; // -1 only during first iteration
320 int nextPollTimeoutMillis = 0;
Jeff Browned739322010-09-21 15:14:14 -0700321 for (;;) {
322 if (nextPollTimeoutMillis != 0) {
323 Binder.flushPendingCommands();
324 }
Jeff Brown013cf842013-09-06 16:24:36 -0700325
Jeff Brown60583902013-09-09 16:14:20 -0700326 nativePollOnce(ptr, nextPollTimeoutMillis);
Christopher Tatefa9e7c02010-05-06 12:07:10 -0700327
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800328 synchronized (this) {
Jeff Browned739322010-09-21 15:14:14 -0700329 // Try to retrieve the next message. Return if found.
330 final long now = SystemClock.uptimeMillis();
Jeff Browne799cb72012-02-14 11:53:33 -0800331 Message prevMsg = null;
332 Message msg = mMessages;
Jeff Brown0f85ce32012-02-16 14:41:10 -0800333 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) {
Jeff Browne799cb72012-02-14 11:53:33 -0800342 // Next message is not ready. Set a timeout to wake up when it is ready.
Jeff Brown0f85ce32012-02-16 14:41:10 -0800343 nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
344 } else {
Jeff Browne799cb72012-02-14 11:53:33 -0800345 // Got a message.
Jeff Brown415d8c32010-10-05 15:35:37 -0700346 mBlocked = false;
Jeff Browne799cb72012-02-14 11:53:33 -0800347 if (prevMsg != null) {
348 prevMsg.next = msg.next;
349 } else {
350 mMessages = msg.next;
351 }
Jeff Brown415d8c32010-10-05 15:35:37 -0700352 msg.next = null;
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800353 if (DEBUG) Log.v(TAG, "Returning message: " + msg);
354 msg.markInUse();
Jeff Browned739322010-09-21 15:14:14 -0700355 return msg;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800356 }
Jeff Brown0f85ce32012-02-16 14:41:10 -0800357 } else {
358 // No more messages.
359 nextPollTimeoutMillis = -1;
Jeff Browned739322010-09-21 15:14:14 -0700360 }
361
Jeff Brown024136f2013-04-11 19:21:32 -0700362 // Process the quit message now that all pending messages have been handled.
Jeff Brown013cf842013-09-06 16:24:36 -0700363 if (mQuitting) {
Jeff Brown024136f2013-04-11 19:21:32 -0700364 dispose();
365 return null;
366 }
367
Jeff Browne799cb72012-02-14 11:53:33 -0800368 // If first time idle, then get the number of idlers to run.
Jeff Brown0f85ce32012-02-16 14:41:10 -0800369 // 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)) {
Jeff Browned739322010-09-21 15:14:14 -0700373 pendingIdleHandlerCount = mIdleHandlers.size();
374 }
Jeff Browne799cb72012-02-14 11:53:33 -0800375 if (pendingIdleHandlerCount <= 0) {
Jeff Browned739322010-09-21 15:14:14 -0700376 // No idle handlers to run. Loop and wait some more.
Jeff Brown415d8c32010-10-05 15:35:37 -0700377 mBlocked = true;
Jeff Browned739322010-09-21 15:14:14 -0700378 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) {
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800397 Log.wtf(TAG, "IdleHandler threw exception", t);
Jeff Browned739322010-09-21 15:14:14 -0700398 }
399
400 if (!keep) {
401 synchronized (this) {
402 mIdleHandlers.remove(idler);
403 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800404 }
405 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800406
Jeff Browned739322010-09-21 15:14:14 -0700407 // Reset the idle handler count to 0 so we do not run them again.
408 pendingIdleHandlerCount = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800409
Jeff Browned739322010-09-21 15:14:14 -0700410 // 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 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800414 }
415
Jeff Brown8b60e452013-04-18 15:17:48 -0700416 void quit(boolean safe) {
Jeff Brown0f85ce32012-02-16 14:41:10 -0800417 if (!mQuitAllowed) {
Jeff Brown9867ed72014-02-28 14:00:57 -0800418 throw new IllegalStateException("Main thread not allowed to quit.");
Jeff Brown0f85ce32012-02-16 14:41:10 -0800419 }
420
421 synchronized (this) {
Jeff Brown013cf842013-09-06 16:24:36 -0700422 if (mQuitting) {
Jeff Brown0f85ce32012-02-16 14:41:10 -0800423 return;
424 }
Jeff Brown013cf842013-09-06 16:24:36 -0700425 mQuitting = true;
Jeff Brown8b60e452013-04-18 15:17:48 -0700426
427 if (safe) {
428 removeAllFutureMessagesLocked();
429 } else {
430 removeAllMessagesLocked();
431 }
Jeff Brown013cf842013-09-06 16:24:36 -0700432
433 // We can assume mPtr != 0 because mQuitting was previously false.
434 nativeWake(mPtr);
Jeff Brown0f85ce32012-02-16 14:41:10 -0800435 }
Jeff Brown0f85ce32012-02-16 14:41:10 -0800436 }
437
Jeff Brown3d4e7efe2015-02-26 15:34:16 -0800438 /**
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 */
461 public int postSyncBarrier() {
462 return postSyncBarrier(SystemClock.uptimeMillis());
463 }
464
465 private int postSyncBarrier(long when) {
Jeff Brown0f85ce32012-02-16 14:41:10 -0800466 // 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();
Jeff Brown9867ed72014-02-28 14:00:57 -0800471 msg.markInUse();
Jeff Brown5182c782013-10-15 20:31:52 -0700472 msg.when = when;
Jeff Brown0f85ce32012-02-16 14:41:10 -0800473 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
Jeff Brown3d4e7efe2015-02-26 15:34:16 -0800494 /**
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 */
504 public void removeSyncBarrier(int token) {
Jeff Brown0f85ce32012-02-16 14:41:10 -0800505 // Remove a sync barrier token from the queue.
506 // If the queue is no longer stalled by a barrier then wake it.
Jeff Brown0f85ce32012-02-16 14:41:10 -0800507 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 }
Jeff Brown013cf842013-09-06 16:24:36 -0700518 final boolean needWake;
Jeff Brown0f85ce32012-02-16 14:41:10 -0800519 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 }
Jeff Brown9867ed72014-02-28 14:00:57 -0800526 p.recycleUnchecked();
Jeff Brown013cf842013-09-06 16:24:36 -0700527
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 }
Jeff Brown0f85ce32012-02-16 14:41:10 -0800533 }
534 }
535
Jeff Brown67fc67c2013-04-01 13:00:33 -0700536 boolean enqueueMessage(Message msg, long when) {
Jeff Brown0f85ce32012-02-16 14:41:10 -0800537 if (msg.target == null) {
Jeff Brown9867ed72014-02-28 14:00:57 -0800538 throw new IllegalArgumentException("Message must have a target.");
539 }
540 if (msg.isInUse()) {
541 throw new IllegalStateException(msg + " This message is already in use.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800542 }
Jeff Brown0f85ce32012-02-16 14:41:10 -0800543
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800544 synchronized (this) {
Jeff Brown013cf842013-09-06 16:24:36 -0700545 if (mQuitting) {
Jeff Brown9867ed72014-02-28 14:00:57 -0800546 IllegalStateException e = new IllegalStateException(
Jeff Brown0f85ce32012-02-16 14:41:10 -0800547 msg.target + " sending message to a Handler on a dead thread");
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800548 Log.w(TAG, e.getMessage(), e);
Jeff Brown9867ed72014-02-28 14:00:57 -0800549 msg.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800550 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800551 }
552
Jeff Brown9867ed72014-02-28 14:00:57 -0800553 msg.markInUse();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800554 msg.when = when;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800555 Message p = mMessages;
Jeff Brown013cf842013-09-06 16:24:36 -0700556 boolean needWake;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800557 if (p == null || when == 0 || when < p.when) {
Jeff Browne799cb72012-02-14 11:53:33 -0800558 // New head, wake up the event queue if blocked.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800559 msg.next = p;
560 mMessages = msg;
Jeff Browne799cb72012-02-14 11:53:33 -0800561 needWake = mBlocked;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800562 } else {
Jeff Browne799cb72012-02-14 11:53:33 -0800563 // Inserted within the middle of the queue. Usually we don't have to wake
Jeff Brown0f85ce32012-02-16 14:41:10 -0800564 // 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 (;;) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800569 prev = p;
570 p = p.next;
Jeff Brown0f85ce32012-02-16 14:41:10 -0800571 if (p == null || when < p.when) {
572 break;
573 }
574 if (needWake && p.isAsynchronous()) {
575 needWake = false;
576 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800577 }
Jeff Brown0f85ce32012-02-16 14:41:10 -0800578 msg.next = p; // invariant: p == prev.next
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800579 prev.next = msg;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800580 }
Jeff Brown013cf842013-09-06 16:24:36 -0700581
582 // We can assume mPtr != 0 because mQuitting is false.
583 if (needWake) {
584 nativeWake(mPtr);
585 }
Jeff Brown415d8c32010-10-05 15:35:37 -0700586 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800587 return true;
588 }
589
Jeff Brown67fc67c2013-04-01 13:00:33 -0700590 boolean hasMessages(Handler h, int what, Object object) {
Jeff Brown0f85ce32012-02-16 14:41:10 -0800591 if (h == null) {
592 return false;
593 }
594
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800595 synchronized (this) {
596 Message p = mMessages;
Jeff Brown0f85ce32012-02-16 14:41:10 -0800597 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
Jeff Brown67fc67c2013-04-01 13:00:33 -0700607 boolean hasMessages(Handler h, Runnable r, Object object) {
Romain Guyba6be8a2012-04-23 18:22:09 -0700608 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
Dianne Hackborncb015632017-06-14 17:30:15 -0700624 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
Jeff Brown67fc67c2013-04-01 13:00:33 -0700641 void removeMessages(Handler h, int what, Object object) {
Jeff Brown0f85ce32012-02-16 14:41:10 -0800642 if (h == null) {
643 return;
644 }
645
646 synchronized (this) {
647 Message p = mMessages;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800648
649 // Remove all messages at front.
650 while (p != null && p.target == h && p.what == what
651 && (object == null || p.obj == object)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800652 Message n = p.next;
653 mMessages = n;
Jeff Brown9867ed72014-02-28 14:00:57 -0800654 p.recycleUnchecked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800655 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)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800664 Message nn = n.next;
Jeff Brown9867ed72014-02-28 14:00:57 -0800665 n.recycleUnchecked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800666 p.next = nn;
667 continue;
668 }
669 }
670 p = n;
671 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800672 }
673 }
674
Jeff Brown67fc67c2013-04-01 13:00:33 -0700675 void removeMessages(Handler h, Runnable r, Object object) {
Jeff Brown0f85ce32012-02-16 14:41:10 -0800676 if (h == null || r == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800677 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;
Jeff Brown9867ed72014-02-28 14:00:57 -0800688 p.recycleUnchecked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800689 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;
Jeff Brown9867ed72014-02-28 14:00:57 -0800699 n.recycleUnchecked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800700 p.next = nn;
701 continue;
702 }
703 }
704 p = n;
705 }
706 }
707 }
708
Jeff Brown67fc67c2013-04-01 13:00:33 -0700709 void removeCallbacksAndMessages(Handler h, Object object) {
Jeff Brown0f85ce32012-02-16 14:41:10 -0800710 if (h == null) {
711 return;
712 }
713
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800714 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;
Jeff Brown9867ed72014-02-28 14:00:57 -0800722 p.recycleUnchecked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800723 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;
Jeff Brown9867ed72014-02-28 14:00:57 -0800732 n.recycleUnchecked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800733 p.next = nn;
734 continue;
735 }
736 }
737 p = n;
738 }
739 }
740 }
Jeff Brown8b60e452013-04-18 15:17:48 -0700741
742 private void removeAllMessagesLocked() {
743 Message p = mMessages;
744 while (p != null) {
745 Message n = p.next;
Jeff Brown9867ed72014-02-28 14:00:57 -0800746 p.recycleUnchecked();
Jeff Brown8b60e452013-04-18 15:17:48 -0700747 p = n;
748 }
749 mMessages = null;
750 }
751
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;
Jeff Brown9867ed72014-02-28 14:00:57 -0800774 p.recycleUnchecked();
Jeff Brown8b60e452013-04-18 15:17:48 -0700775 } while (n != null);
776 }
777 }
778 }
Jeff Brown5182c782013-10-15 20:31:52 -0700779
Dianne Hackborncb015632017-06-14 17:30:15 -0700780 void dump(Printer pw, String prefix, Handler h) {
Jeff Brown5182c782013-10-15 20:31:52 -0700781 synchronized (this) {
782 long now = SystemClock.uptimeMillis();
783 int n = 0;
784 for (Message msg = mMessages; msg != null; msg = msg.next) {
Dianne Hackborncb015632017-06-14 17:30:15 -0700785 if (h == null || h == msg.target) {
786 pw.println(prefix + "Message " + n + ": " + msg.toString(now));
787 }
Jeff Brown5182c782013-10-15 20:31:52 -0700788 n++;
789 }
Jeff Brown6c7b41a2015-02-26 14:43:53 -0800790 pw.println(prefix + "(Total messages: " + n + ", polling=" + isPollingLocked()
Jeff Brown5182c782013-10-15 20:31:52 -0700791 + ", quitting=" + mQuitting + ")");
792 }
793 }
Jeff Brown6c7b41a2015-02-26 14:43:53 -0800794
Netta P958d0a52017-02-07 11:20:55 -0800795 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
Jeff Brown6c7b41a2015-02-26 14:43:53 -0800807 /**
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 */
819 boolean queueIdle();
820 }
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800821
822 /**
Jeff Brown3f640522015-05-15 12:26:15 -0700823 * A listener which is invoked when file descriptor related events occur.
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800824 */
Jeff Brown3f640522015-05-15 12:26:15 -0700825 public interface OnFileDescriptorEventListener {
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800826 /**
827 * File descriptor event: Indicates that the file descriptor is ready for input
828 * operations, such as reading.
829 * <p>
Jeff Brown3f640522015-05-15 12:26:15 -0700830 * 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.
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800833 * </p><p>
834 * In the case of a socket, this event may be generated to indicate
Jeff Brown3f640522015-05-15 12:26:15 -0700835 * that there is at least one incoming connection that the listener
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800836 * should accept.
837 * </p><p>
838 * This event will only be generated if the {@link #EVENT_INPUT} event mask was
Jeff Brown3f640522015-05-15 12:26:15 -0700839 * specified when the listener was added.
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800840 * </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>
Jeff Brown3f640522015-05-15 12:26:15 -0700848 * The listener should write as much data as it needs. If it could not
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800849 * write everything at once, then it should return <code>true</code> to
Jeff Brown3f640522015-05-15 12:26:15 -0700850 * 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
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800852 * something else.
853 * </p><p>
854 * This event will only be generated if the {@link #EVENT_OUTPUT} event mask was
Jeff Brown3f640522015-05-15 12:26:15 -0700855 * specified when the listener was added.
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800856 * </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
Jeff Brown3f640522015-05-15 12:26:15 -0700868 * {@link #EVENT_ERROR} event mask was specified when the listener was added.
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800869 * </p>
870 */
871 public static final int EVENT_ERROR = 1 << 2;
872
873 /** @hide */
874 @Retention(RetentionPolicy.SOURCE)
Jeff Sharkeyce8db992017-12-13 20:05:05 -0700875 @IntDef(flag = true, prefix = { "EVENT_" }, value = {
876 EVENT_INPUT,
877 EVENT_OUTPUT,
878 EVENT_ERROR
879 })
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800880 public @interface Events {}
881
882 /**
883 * Called when a file descriptor receives events.
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800884 *
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.
Jeff Brown3f640522015-05-15 12:26:15 -0700888 * @return The new set of events to watch, or 0 to unregister the listener.
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800889 *
890 * @see #EVENT_INPUT
891 * @see #EVENT_OUTPUT
892 * @see #EVENT_ERROR
893 */
Jeff Brown3f640522015-05-15 12:26:15 -0700894 @Events int onFileDescriptorEvents(@NonNull FileDescriptor fd, @Events int events);
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800895 }
896
897 private static final class FileDescriptorRecord {
898 public final FileDescriptor mDescriptor;
899 public int mEvents;
Jeff Brown3f640522015-05-15 12:26:15 -0700900 public OnFileDescriptorEventListener mListener;
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800901 public int mSeq;
902
903 public FileDescriptorRecord(FileDescriptor descriptor,
Jeff Brown3f640522015-05-15 12:26:15 -0700904 int events, OnFileDescriptorEventListener listener) {
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800905 mDescriptor = descriptor;
906 mEvents = events;
Jeff Brown3f640522015-05-15 12:26:15 -0700907 mListener = listener;
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800908 }
909 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800910}