blob: f98fdc393de3bc48c7858f25cb2e2c9030d4ca1d [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;
Jeff Sharkeyc6091162018-06-29 17:15:40 -060021import android.annotation.TestApi;
Andrei Onea24ec3212019-03-15 17:35:05 +000022import android.annotation.UnsupportedAppUsage;
Netta P958d0a52017-02-07 11:20:55 -080023import android.os.MessageQueueProto;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080024import android.util.Log;
Jeff Brown5182c782013-10-15 20:31:52 -070025import android.util.Printer;
Jeff Browndc3eb4b2015-03-05 18:21:06 -080026import android.util.SparseArray;
Netta P958d0a52017-02-07 11:20:55 -080027import android.util.proto.ProtoOutputStream;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080028
Jeff Browndc3eb4b2015-03-05 18:21:06 -080029import java.io.FileDescriptor;
30import java.lang.annotation.Retention;
31import java.lang.annotation.RetentionPolicy;
Jeff Brown46b9ac02010-04-22 18:58:52 -070032import java.util.ArrayList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080033
34/**
35 * Low-level class holding the list of messages to be dispatched by a
36 * {@link Looper}. Messages are not added directly to a MessageQueue,
37 * but rather through {@link Handler} objects associated with the Looper.
Netta P958d0a52017-02-07 11:20:55 -080038 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039 * <p>You can retrieve the MessageQueue for the current thread with
40 * {@link Looper#myQueue() Looper.myQueue()}.
41 */
Jeff Brown67fc67c2013-04-01 13:00:33 -070042public final class MessageQueue {
Jeff Browndc3eb4b2015-03-05 18:21:06 -080043 private static final String TAG = "MessageQueue";
44 private static final boolean DEBUG = false;
45
Jeff Brown0f85ce32012-02-16 14:41:10 -080046 // True if the message queue can be quit.
Andrei Onea24ec3212019-03-15 17:35:05 +000047 @UnsupportedAppUsage
Jeff Brown0f85ce32012-02-16 14:41:10 -080048 private final boolean mQuitAllowed;
49
Andrei Onea24ec3212019-03-15 17:35:05 +000050 @UnsupportedAppUsage
Jeff Brown0f85ce32012-02-16 14:41:10 -080051 @SuppressWarnings("unused")
Ashok Bhat63a37152014-01-10 14:15:21 +000052 private long mPtr; // used by native code
Jeff Brown0f85ce32012-02-16 14:41:10 -080053
Andrei Onea24ec3212019-03-15 17:35:05 +000054 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055 Message mMessages;
Andrei Onea24ec3212019-03-15 17:35:05 +000056 @UnsupportedAppUsage
Jeff Brown46b9ac02010-04-22 18:58:52 -070057 private final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<IdleHandler>();
Jeff Browndc3eb4b2015-03-05 18:21:06 -080058 private SparseArray<FileDescriptorRecord> mFileDescriptorRecords;
Jeff Browned739322010-09-21 15:14:14 -070059 private IdleHandler[] mPendingIdleHandlers;
Jeff Brown013cf842013-09-06 16:24:36 -070060 private boolean mQuitting;
Christopher Tatefa9e7c02010-05-06 12:07:10 -070061
Jeff Brown415d8c32010-10-05 15:35:37 -070062 // Indicates whether next() is blocked waiting in pollOnce() with a non-zero timeout.
63 private boolean mBlocked;
64
Jeff Brown0f85ce32012-02-16 14:41:10 -080065 // The next barrier token.
66 // Barriers are indicated by messages with a null target whose arg1 field carries the token.
Andrei Onea24ec3212019-03-15 17:35:05 +000067 @UnsupportedAppUsage
Jeff Brown0f85ce32012-02-16 14:41:10 -080068 private int mNextBarrierToken;
Jeff Browne799cb72012-02-14 11:53:33 -080069
Ashok Bhat63a37152014-01-10 14:15:21 +000070 private native static long nativeInit();
71 private native static void nativeDestroy(long ptr);
Andrei Onea24ec3212019-03-15 17:35:05 +000072 @UnsupportedAppUsage
Jeff Browndc3eb4b2015-03-05 18:21:06 -080073 private native void nativePollOnce(long ptr, int timeoutMillis); /*non-static for callbacks*/
Ashok Bhat63a37152014-01-10 14:15:21 +000074 private native static void nativeWake(long ptr);
Jeff Brown6c7b41a2015-02-26 14:43:53 -080075 private native static boolean nativeIsPolling(long ptr);
Jeff Browndc3eb4b2015-03-05 18:21:06 -080076 private native static void nativeSetFileDescriptorEvents(long ptr, int fd, int events);
Jeff Browne799cb72012-02-14 11:53:33 -080077
Jeff Brown0f85ce32012-02-16 14:41:10 -080078 MessageQueue(boolean quitAllowed) {
79 mQuitAllowed = quitAllowed;
Jeff Brown864693462013-01-28 14:25:53 -080080 mPtr = nativeInit();
Christopher Tatefa9e7c02010-05-06 12:07:10 -070081 }
Jeff Brown0f85ce32012-02-16 14:41:10 -080082
Jeff Brown46b9ac02010-04-22 18:58:52 -070083 @Override
84 protected void finalize() throws Throwable {
85 try {
Jeff Brown864693462013-01-28 14:25:53 -080086 dispose();
Jeff Brown46b9ac02010-04-22 18:58:52 -070087 } finally {
88 super.finalize();
89 }
90 }
Christopher Tatefa9e7c02010-05-06 12:07:10 -070091
Jeff Brown013cf842013-09-06 16:24:36 -070092 // Disposes of the underlying message queue.
93 // Must only be called on the looper thread or the finalizer.
Jeff Brown864693462013-01-28 14:25:53 -080094 private void dispose() {
95 if (mPtr != 0) {
96 nativeDestroy(mPtr);
97 mPtr = 0;
98 }
99 }
100
Jeff Brown6c7b41a2015-02-26 14:43:53 -0800101 /**
102 * Returns true if the looper has no pending messages which are due to be processed.
103 *
104 * <p>This method is safe to call from any thread.
105 *
106 * @return True if the looper is idle.
107 */
108 public boolean isIdle() {
109 synchronized (this) {
110 final long now = SystemClock.uptimeMillis();
111 return mMessages == null || now < mMessages.when;
112 }
113 }
114
115 /**
116 * Add a new {@link IdleHandler} to this message queue. This may be
117 * removed automatically for you by returning false from
118 * {@link IdleHandler#queueIdle IdleHandler.queueIdle()} when it is
119 * invoked, or explicitly removing it with {@link #removeIdleHandler}.
120 *
121 * <p>This method is safe to call from any thread.
122 *
123 * @param handler The IdleHandler to be added.
124 */
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800125 public void addIdleHandler(@NonNull IdleHandler handler) {
Jeff Brown6c7b41a2015-02-26 14:43:53 -0800126 if (handler == null) {
127 throw new NullPointerException("Can't add a null IdleHandler");
128 }
129 synchronized (this) {
130 mIdleHandlers.add(handler);
131 }
132 }
133
134 /**
135 * Remove an {@link IdleHandler} from the queue that was previously added
136 * with {@link #addIdleHandler}. If the given object is not currently
137 * in the idle list, nothing is done.
138 *
139 * <p>This method is safe to call from any thread.
140 *
141 * @param handler The IdleHandler to be removed.
142 */
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800143 public void removeIdleHandler(@NonNull IdleHandler handler) {
Jeff Brown6c7b41a2015-02-26 14:43:53 -0800144 synchronized (this) {
145 mIdleHandlers.remove(handler);
146 }
147 }
148
149 /**
150 * Returns whether this looper's thread is currently polling for more work to do.
151 * This is a good signal that the loop is still alive rather than being stuck
152 * handling a callback. Note that this method is intrinsically racy, since the
153 * state of the loop can change before you get the result back.
154 *
155 * <p>This method is safe to call from any thread.
156 *
157 * @return True if the looper is currently polling for events.
158 * @hide
159 */
160 public boolean isPolling() {
161 synchronized (this) {
162 return isPollingLocked();
163 }
164 }
165
166 private boolean isPollingLocked() {
167 // If the loop is quitting then it must not be idling.
168 // We can assume mPtr != 0 when mQuitting is false.
169 return !mQuitting && nativeIsPolling(mPtr);
170 }
171
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800172 /**
Jeff Brown3f640522015-05-15 12:26:15 -0700173 * Adds a file descriptor listener to receive notification when file descriptor
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800174 * related events occur.
175 * <p>
176 * If the file descriptor has already been registered, the specified events
Jeff Brown3f640522015-05-15 12:26:15 -0700177 * and listener will replace any that were previously associated with it.
178 * It is not possible to set more than one listener per file descriptor.
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800179 * </p><p>
Jeff Brown3f640522015-05-15 12:26:15 -0700180 * It is important to always unregister the listener when the file descriptor
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800181 * is no longer of use.
182 * </p>
183 *
Jeff Brown3f640522015-05-15 12:26:15 -0700184 * @param fd The file descriptor for which a listener will be registered.
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800185 * @param events The set of events to receive: a combination of the
Jeff Brown3f640522015-05-15 12:26:15 -0700186 * {@link OnFileDescriptorEventListener#EVENT_INPUT},
187 * {@link OnFileDescriptorEventListener#EVENT_OUTPUT}, and
188 * {@link OnFileDescriptorEventListener#EVENT_ERROR} event masks. If the requested
189 * set of events is zero, then the listener is unregistered.
190 * @param listener The listener to invoke when file descriptor events occur.
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800191 *
Jeff Brown3f640522015-05-15 12:26:15 -0700192 * @see OnFileDescriptorEventListener
193 * @see #removeOnFileDescriptorEventListener
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800194 */
Jeff Brown3f640522015-05-15 12:26:15 -0700195 public void addOnFileDescriptorEventListener(@NonNull FileDescriptor fd,
196 @OnFileDescriptorEventListener.Events int events,
197 @NonNull OnFileDescriptorEventListener listener) {
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800198 if (fd == null) {
199 throw new IllegalArgumentException("fd must not be null");
200 }
Jeff Brown3f640522015-05-15 12:26:15 -0700201 if (listener == null) {
202 throw new IllegalArgumentException("listener must not be null");
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800203 }
204
205 synchronized (this) {
Jeff Brown3f640522015-05-15 12:26:15 -0700206 updateOnFileDescriptorEventListenerLocked(fd, events, listener);
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800207 }
208 }
209
210 /**
Jeff Brown3f640522015-05-15 12:26:15 -0700211 * Removes a file descriptor listener.
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800212 * <p>
Jeff Brown3f640522015-05-15 12:26:15 -0700213 * This method does nothing if no listener has been registered for the
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800214 * specified file descriptor.
215 * </p>
216 *
Jeff Brown3f640522015-05-15 12:26:15 -0700217 * @param fd The file descriptor whose listener will be unregistered.
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800218 *
Jeff Brown3f640522015-05-15 12:26:15 -0700219 * @see OnFileDescriptorEventListener
220 * @see #addOnFileDescriptorEventListener
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800221 */
Jeff Brown3f640522015-05-15 12:26:15 -0700222 public void removeOnFileDescriptorEventListener(@NonNull FileDescriptor fd) {
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800223 if (fd == null) {
224 throw new IllegalArgumentException("fd must not be null");
225 }
226
227 synchronized (this) {
Jeff Brown3f640522015-05-15 12:26:15 -0700228 updateOnFileDescriptorEventListenerLocked(fd, 0, null);
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800229 }
230 }
231
Jeff Brown3f640522015-05-15 12:26:15 -0700232 private void updateOnFileDescriptorEventListenerLocked(FileDescriptor fd, int events,
233 OnFileDescriptorEventListener listener) {
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800234 final int fdNum = fd.getInt$();
235
236 int index = -1;
237 FileDescriptorRecord record = null;
238 if (mFileDescriptorRecords != null) {
239 index = mFileDescriptorRecords.indexOfKey(fdNum);
240 if (index >= 0) {
241 record = mFileDescriptorRecords.valueAt(index);
242 if (record != null && record.mEvents == events) {
243 return;
244 }
245 }
246 }
247
248 if (events != 0) {
Jeff Brown3f640522015-05-15 12:26:15 -0700249 events |= OnFileDescriptorEventListener.EVENT_ERROR;
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800250 if (record == null) {
251 if (mFileDescriptorRecords == null) {
252 mFileDescriptorRecords = new SparseArray<FileDescriptorRecord>();
253 }
Jeff Brown3f640522015-05-15 12:26:15 -0700254 record = new FileDescriptorRecord(fd, events, listener);
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800255 mFileDescriptorRecords.put(fdNum, record);
256 } else {
Jeff Brown3f640522015-05-15 12:26:15 -0700257 record.mListener = listener;
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800258 record.mEvents = events;
259 record.mSeq += 1;
260 }
261 nativeSetFileDescriptorEvents(mPtr, fdNum, events);
262 } else if (record != null) {
263 record.mEvents = 0;
264 mFileDescriptorRecords.removeAt(index);
David Pursellc16b7752017-08-07 16:32:36 -0700265 nativeSetFileDescriptorEvents(mPtr, fdNum, 0);
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800266 }
267 }
268
269 // Called from native code.
Andrei Onea24ec3212019-03-15 17:35:05 +0000270 @UnsupportedAppUsage
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800271 private int dispatchEvents(int fd, int events) {
272 // Get the file descriptor record and any state that might change.
273 final FileDescriptorRecord record;
274 final int oldWatchedEvents;
Jeff Brown3f640522015-05-15 12:26:15 -0700275 final OnFileDescriptorEventListener listener;
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800276 final int seq;
277 synchronized (this) {
278 record = mFileDescriptorRecords.get(fd);
279 if (record == null) {
Jeff Brown3f640522015-05-15 12:26:15 -0700280 return 0; // spurious, no listener registered
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800281 }
282
283 oldWatchedEvents = record.mEvents;
284 events &= oldWatchedEvents; // filter events based on current watched set
285 if (events == 0) {
286 return oldWatchedEvents; // spurious, watched events changed
287 }
288
Jeff Brown3f640522015-05-15 12:26:15 -0700289 listener = record.mListener;
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800290 seq = record.mSeq;
291 }
292
Jeff Brown3f640522015-05-15 12:26:15 -0700293 // Invoke the listener outside of the lock.
294 int newWatchedEvents = listener.onFileDescriptorEvents(
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800295 record.mDescriptor, events);
296 if (newWatchedEvents != 0) {
Jeff Brown3f640522015-05-15 12:26:15 -0700297 newWatchedEvents |= OnFileDescriptorEventListener.EVENT_ERROR;
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800298 }
299
Jeff Brown3f640522015-05-15 12:26:15 -0700300 // Update the file descriptor record if the listener changed the set of
301 // events to watch and the listener itself hasn't been updated since.
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800302 if (newWatchedEvents != oldWatchedEvents) {
303 synchronized (this) {
304 int index = mFileDescriptorRecords.indexOfKey(fd);
305 if (index >= 0 && mFileDescriptorRecords.valueAt(index) == record
306 && record.mSeq == seq) {
307 record.mEvents = newWatchedEvents;
308 if (newWatchedEvents == 0) {
309 mFileDescriptorRecords.removeAt(index);
310 }
311 }
312 }
313 }
314
315 // Return the new set of events to watch for native code to take care of.
316 return newWatchedEvents;
317 }
318
Andrei Onea24ec3212019-03-15 17:35:05 +0000319 @UnsupportedAppUsage
Jeff Brown67fc67c2013-04-01 13:00:33 -0700320 Message next() {
Jeff Brown60583902013-09-09 16:14:20 -0700321 // Return here if the message loop has already quit and been disposed.
322 // This can happen if the application tries to restart a looper after quit
323 // which is not supported.
Narayan Kamathab864342014-01-16 11:22:52 +0000324 final long ptr = mPtr;
Jeff Brown60583902013-09-09 16:14:20 -0700325 if (ptr == 0) {
326 return null;
327 }
328
Jeff Browned739322010-09-21 15:14:14 -0700329 int pendingIdleHandlerCount = -1; // -1 only during first iteration
330 int nextPollTimeoutMillis = 0;
Jeff Browned739322010-09-21 15:14:14 -0700331 for (;;) {
332 if (nextPollTimeoutMillis != 0) {
333 Binder.flushPendingCommands();
334 }
Jeff Brown013cf842013-09-06 16:24:36 -0700335
Jeff Brown60583902013-09-09 16:14:20 -0700336 nativePollOnce(ptr, nextPollTimeoutMillis);
Christopher Tatefa9e7c02010-05-06 12:07:10 -0700337
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800338 synchronized (this) {
Jeff Browned739322010-09-21 15:14:14 -0700339 // Try to retrieve the next message. Return if found.
340 final long now = SystemClock.uptimeMillis();
Jeff Browne799cb72012-02-14 11:53:33 -0800341 Message prevMsg = null;
342 Message msg = mMessages;
Jeff Brown0f85ce32012-02-16 14:41:10 -0800343 if (msg != null && msg.target == null) {
344 // Stalled by a barrier. Find the next asynchronous message in the queue.
345 do {
346 prevMsg = msg;
347 msg = msg.next;
348 } while (msg != null && !msg.isAsynchronous());
349 }
350 if (msg != null) {
351 if (now < msg.when) {
Jeff Browne799cb72012-02-14 11:53:33 -0800352 // Next message is not ready. Set a timeout to wake up when it is ready.
Jeff Brown0f85ce32012-02-16 14:41:10 -0800353 nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
354 } else {
Jeff Browne799cb72012-02-14 11:53:33 -0800355 // Got a message.
Jeff Brown415d8c32010-10-05 15:35:37 -0700356 mBlocked = false;
Jeff Browne799cb72012-02-14 11:53:33 -0800357 if (prevMsg != null) {
358 prevMsg.next = msg.next;
359 } else {
360 mMessages = msg.next;
361 }
Jeff Brown415d8c32010-10-05 15:35:37 -0700362 msg.next = null;
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800363 if (DEBUG) Log.v(TAG, "Returning message: " + msg);
364 msg.markInUse();
Jeff Browned739322010-09-21 15:14:14 -0700365 return msg;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800366 }
Jeff Brown0f85ce32012-02-16 14:41:10 -0800367 } else {
368 // No more messages.
369 nextPollTimeoutMillis = -1;
Jeff Browned739322010-09-21 15:14:14 -0700370 }
371
Jeff Brown024136f2013-04-11 19:21:32 -0700372 // Process the quit message now that all pending messages have been handled.
Jeff Brown013cf842013-09-06 16:24:36 -0700373 if (mQuitting) {
Jeff Brown024136f2013-04-11 19:21:32 -0700374 dispose();
375 return null;
376 }
377
Jeff Browne799cb72012-02-14 11:53:33 -0800378 // If first time idle, then get the number of idlers to run.
Jeff Brown0f85ce32012-02-16 14:41:10 -0800379 // Idle handles only run if the queue is empty or if the first message
380 // in the queue (possibly a barrier) is due to be handled in the future.
381 if (pendingIdleHandlerCount < 0
382 && (mMessages == null || now < mMessages.when)) {
Jeff Browned739322010-09-21 15:14:14 -0700383 pendingIdleHandlerCount = mIdleHandlers.size();
384 }
Jeff Browne799cb72012-02-14 11:53:33 -0800385 if (pendingIdleHandlerCount <= 0) {
Jeff Browned739322010-09-21 15:14:14 -0700386 // No idle handlers to run. Loop and wait some more.
Jeff Brown415d8c32010-10-05 15:35:37 -0700387 mBlocked = true;
Jeff Browned739322010-09-21 15:14:14 -0700388 continue;
389 }
390
391 if (mPendingIdleHandlers == null) {
392 mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
393 }
394 mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
395 }
396
397 // Run the idle handlers.
398 // We only ever reach this code block during the first iteration.
399 for (int i = 0; i < pendingIdleHandlerCount; i++) {
400 final IdleHandler idler = mPendingIdleHandlers[i];
401 mPendingIdleHandlers[i] = null; // release the reference to the handler
402
403 boolean keep = false;
404 try {
405 keep = idler.queueIdle();
406 } catch (Throwable t) {
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800407 Log.wtf(TAG, "IdleHandler threw exception", t);
Jeff Browned739322010-09-21 15:14:14 -0700408 }
409
410 if (!keep) {
411 synchronized (this) {
412 mIdleHandlers.remove(idler);
413 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800414 }
415 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800416
Jeff Browned739322010-09-21 15:14:14 -0700417 // Reset the idle handler count to 0 so we do not run them again.
418 pendingIdleHandlerCount = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800419
Jeff Browned739322010-09-21 15:14:14 -0700420 // While calling an idle handler, a new message could have been delivered
421 // so go back and look again for a pending message without waiting.
422 nextPollTimeoutMillis = 0;
423 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800424 }
425
Jeff Brown8b60e452013-04-18 15:17:48 -0700426 void quit(boolean safe) {
Jeff Brown0f85ce32012-02-16 14:41:10 -0800427 if (!mQuitAllowed) {
Jeff Brown9867ed72014-02-28 14:00:57 -0800428 throw new IllegalStateException("Main thread not allowed to quit.");
Jeff Brown0f85ce32012-02-16 14:41:10 -0800429 }
430
431 synchronized (this) {
Jeff Brown013cf842013-09-06 16:24:36 -0700432 if (mQuitting) {
Jeff Brown0f85ce32012-02-16 14:41:10 -0800433 return;
434 }
Jeff Brown013cf842013-09-06 16:24:36 -0700435 mQuitting = true;
Jeff Brown8b60e452013-04-18 15:17:48 -0700436
437 if (safe) {
438 removeAllFutureMessagesLocked();
439 } else {
440 removeAllMessagesLocked();
441 }
Jeff Brown013cf842013-09-06 16:24:36 -0700442
443 // We can assume mPtr != 0 because mQuitting was previously false.
444 nativeWake(mPtr);
Jeff Brown0f85ce32012-02-16 14:41:10 -0800445 }
Jeff Brown0f85ce32012-02-16 14:41:10 -0800446 }
447
Jeff Brown3d4e7efe2015-02-26 15:34:16 -0800448 /**
449 * Posts a synchronization barrier to the Looper's message queue.
450 *
451 * Message processing occurs as usual until the message queue encounters the
452 * synchronization barrier that has been posted. When the barrier is encountered,
453 * later synchronous messages in the queue are stalled (prevented from being executed)
454 * until the barrier is released by calling {@link #removeSyncBarrier} and specifying
455 * the token that identifies the synchronization barrier.
456 *
457 * This method is used to immediately postpone execution of all subsequently posted
458 * synchronous messages until a condition is met that releases the barrier.
459 * Asynchronous messages (see {@link Message#isAsynchronous} are exempt from the barrier
460 * and continue to be processed as usual.
461 *
462 * This call must be always matched by a call to {@link #removeSyncBarrier} with
463 * the same token to ensure that the message queue resumes normal operation.
464 * Otherwise the application will probably hang!
465 *
466 * @return A token that uniquely identifies the barrier. This token must be
467 * passed to {@link #removeSyncBarrier} to release the barrier.
468 *
469 * @hide
470 */
Artur Satayevf0b7d0b2019-11-04 11:16:45 +0000471 @UnsupportedAppUsage
Jeff Sharkeyc6091162018-06-29 17:15:40 -0600472 @TestApi
Jeff Brown3d4e7efe2015-02-26 15:34:16 -0800473 public int postSyncBarrier() {
474 return postSyncBarrier(SystemClock.uptimeMillis());
475 }
476
477 private int postSyncBarrier(long when) {
Jeff Brown0f85ce32012-02-16 14:41:10 -0800478 // Enqueue a new sync barrier token.
479 // We don't need to wake the queue because the purpose of a barrier is to stall it.
480 synchronized (this) {
481 final int token = mNextBarrierToken++;
482 final Message msg = Message.obtain();
Jeff Brown9867ed72014-02-28 14:00:57 -0800483 msg.markInUse();
Jeff Brown5182c782013-10-15 20:31:52 -0700484 msg.when = when;
Jeff Brown0f85ce32012-02-16 14:41:10 -0800485 msg.arg1 = token;
486
487 Message prev = null;
488 Message p = mMessages;
489 if (when != 0) {
490 while (p != null && p.when <= when) {
491 prev = p;
492 p = p.next;
493 }
494 }
495 if (prev != null) { // invariant: p == prev.next
496 msg.next = p;
497 prev.next = msg;
498 } else {
499 msg.next = p;
500 mMessages = msg;
501 }
502 return token;
503 }
504 }
505
Jeff Brown3d4e7efe2015-02-26 15:34:16 -0800506 /**
507 * Removes a synchronization barrier.
508 *
509 * @param token The synchronization barrier token that was returned by
510 * {@link #postSyncBarrier}.
511 *
512 * @throws IllegalStateException if the barrier was not found.
513 *
514 * @hide
515 */
Artur Satayevf0b7d0b2019-11-04 11:16:45 +0000516 @UnsupportedAppUsage
Jeff Sharkeyc6091162018-06-29 17:15:40 -0600517 @TestApi
Jeff Brown3d4e7efe2015-02-26 15:34:16 -0800518 public void removeSyncBarrier(int token) {
Jeff Brown0f85ce32012-02-16 14:41:10 -0800519 // Remove a sync barrier token from the queue.
520 // If the queue is no longer stalled by a barrier then wake it.
Jeff Brown0f85ce32012-02-16 14:41:10 -0800521 synchronized (this) {
522 Message prev = null;
523 Message p = mMessages;
524 while (p != null && (p.target != null || p.arg1 != token)) {
525 prev = p;
526 p = p.next;
527 }
528 if (p == null) {
529 throw new IllegalStateException("The specified message queue synchronization "
530 + " barrier token has not been posted or has already been removed.");
531 }
Jeff Brown013cf842013-09-06 16:24:36 -0700532 final boolean needWake;
Jeff Brown0f85ce32012-02-16 14:41:10 -0800533 if (prev != null) {
534 prev.next = p.next;
535 needWake = false;
536 } else {
537 mMessages = p.next;
538 needWake = mMessages == null || mMessages.target != null;
539 }
Jeff Brown9867ed72014-02-28 14:00:57 -0800540 p.recycleUnchecked();
Jeff Brown013cf842013-09-06 16:24:36 -0700541
542 // If the loop is quitting then it is already awake.
543 // We can assume mPtr != 0 when mQuitting is false.
544 if (needWake && !mQuitting) {
545 nativeWake(mPtr);
546 }
Jeff Brown0f85ce32012-02-16 14:41:10 -0800547 }
548 }
549
Jeff Brown67fc67c2013-04-01 13:00:33 -0700550 boolean enqueueMessage(Message msg, long when) {
Jeff Brown0f85ce32012-02-16 14:41:10 -0800551 if (msg.target == null) {
Jeff Brown9867ed72014-02-28 14:00:57 -0800552 throw new IllegalArgumentException("Message must have a target.");
553 }
554 if (msg.isInUse()) {
555 throw new IllegalStateException(msg + " This message is already in use.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800556 }
Jeff Brown0f85ce32012-02-16 14:41:10 -0800557
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800558 synchronized (this) {
Jeff Brown013cf842013-09-06 16:24:36 -0700559 if (mQuitting) {
Jeff Brown9867ed72014-02-28 14:00:57 -0800560 IllegalStateException e = new IllegalStateException(
Jeff Brown0f85ce32012-02-16 14:41:10 -0800561 msg.target + " sending message to a Handler on a dead thread");
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800562 Log.w(TAG, e.getMessage(), e);
Jeff Brown9867ed72014-02-28 14:00:57 -0800563 msg.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800564 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800565 }
566
Jeff Brown9867ed72014-02-28 14:00:57 -0800567 msg.markInUse();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800568 msg.when = when;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800569 Message p = mMessages;
Jeff Brown013cf842013-09-06 16:24:36 -0700570 boolean needWake;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800571 if (p == null || when == 0 || when < p.when) {
Jeff Browne799cb72012-02-14 11:53:33 -0800572 // New head, wake up the event queue if blocked.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800573 msg.next = p;
574 mMessages = msg;
Jeff Browne799cb72012-02-14 11:53:33 -0800575 needWake = mBlocked;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800576 } else {
Jeff Browne799cb72012-02-14 11:53:33 -0800577 // Inserted within the middle of the queue. Usually we don't have to wake
Jeff Brown0f85ce32012-02-16 14:41:10 -0800578 // up the event queue unless there is a barrier at the head of the queue
579 // and the message is the earliest asynchronous message in the queue.
580 needWake = mBlocked && p.target == null && msg.isAsynchronous();
581 Message prev;
582 for (;;) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800583 prev = p;
584 p = p.next;
Jeff Brown0f85ce32012-02-16 14:41:10 -0800585 if (p == null || when < p.when) {
586 break;
587 }
588 if (needWake && p.isAsynchronous()) {
589 needWake = false;
590 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800591 }
Jeff Brown0f85ce32012-02-16 14:41:10 -0800592 msg.next = p; // invariant: p == prev.next
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800593 prev.next = msg;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800594 }
Jeff Brown013cf842013-09-06 16:24:36 -0700595
596 // We can assume mPtr != 0 because mQuitting is false.
597 if (needWake) {
598 nativeWake(mPtr);
599 }
Jeff Brown415d8c32010-10-05 15:35:37 -0700600 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800601 return true;
602 }
603
Jeff Brown67fc67c2013-04-01 13:00:33 -0700604 boolean hasMessages(Handler h, int what, Object object) {
Jeff Brown0f85ce32012-02-16 14:41:10 -0800605 if (h == null) {
606 return false;
607 }
608
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800609 synchronized (this) {
610 Message p = mMessages;
Jeff Brown0f85ce32012-02-16 14:41:10 -0800611 while (p != null) {
612 if (p.target == h && p.what == what && (object == null || p.obj == object)) {
613 return true;
614 }
615 p = p.next;
616 }
617 return false;
618 }
619 }
620
Andrei Onea24ec3212019-03-15 17:35:05 +0000621 @UnsupportedAppUsage
Jeff Brown67fc67c2013-04-01 13:00:33 -0700622 boolean hasMessages(Handler h, Runnable r, Object object) {
Romain Guyba6be8a2012-04-23 18:22:09 -0700623 if (h == null) {
624 return false;
625 }
626
627 synchronized (this) {
628 Message p = mMessages;
629 while (p != null) {
630 if (p.target == h && p.callback == r && (object == null || p.obj == object)) {
631 return true;
632 }
633 p = p.next;
634 }
635 return false;
636 }
637 }
638
Dianne Hackborncb015632017-06-14 17:30:15 -0700639 boolean hasMessages(Handler h) {
640 if (h == null) {
641 return false;
642 }
643
644 synchronized (this) {
645 Message p = mMessages;
646 while (p != null) {
647 if (p.target == h) {
648 return true;
649 }
650 p = p.next;
651 }
652 return false;
653 }
654 }
655
Jeff Brown67fc67c2013-04-01 13:00:33 -0700656 void removeMessages(Handler h, int what, Object object) {
Jeff Brown0f85ce32012-02-16 14:41:10 -0800657 if (h == null) {
658 return;
659 }
660
661 synchronized (this) {
662 Message p = mMessages;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800663
664 // Remove all messages at front.
665 while (p != null && p.target == h && p.what == what
666 && (object == null || p.obj == object)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800667 Message n = p.next;
668 mMessages = n;
Jeff Brown9867ed72014-02-28 14:00:57 -0800669 p.recycleUnchecked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800670 p = n;
671 }
672
673 // Remove all messages after front.
674 while (p != null) {
675 Message n = p.next;
676 if (n != null) {
677 if (n.target == h && n.what == what
678 && (object == null || n.obj == object)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800679 Message nn = n.next;
Jeff Brown9867ed72014-02-28 14:00:57 -0800680 n.recycleUnchecked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800681 p.next = nn;
682 continue;
683 }
684 }
685 p = n;
686 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800687 }
688 }
689
Jeff Brown67fc67c2013-04-01 13:00:33 -0700690 void removeMessages(Handler h, Runnable r, Object object) {
Jeff Brown0f85ce32012-02-16 14:41:10 -0800691 if (h == null || r == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800692 return;
693 }
694
695 synchronized (this) {
696 Message p = mMessages;
697
698 // Remove all messages at front.
699 while (p != null && p.target == h && p.callback == r
700 && (object == null || p.obj == object)) {
701 Message n = p.next;
702 mMessages = n;
Jeff Brown9867ed72014-02-28 14:00:57 -0800703 p.recycleUnchecked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800704 p = n;
705 }
706
707 // Remove all messages after front.
708 while (p != null) {
709 Message n = p.next;
710 if (n != null) {
711 if (n.target == h && n.callback == r
712 && (object == null || n.obj == object)) {
713 Message nn = n.next;
Jeff Brown9867ed72014-02-28 14:00:57 -0800714 n.recycleUnchecked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800715 p.next = nn;
716 continue;
717 }
718 }
719 p = n;
720 }
721 }
722 }
723
Jeff Brown67fc67c2013-04-01 13:00:33 -0700724 void removeCallbacksAndMessages(Handler h, Object object) {
Jeff Brown0f85ce32012-02-16 14:41:10 -0800725 if (h == null) {
726 return;
727 }
728
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800729 synchronized (this) {
730 Message p = mMessages;
731
732 // Remove all messages at front.
733 while (p != null && p.target == h
734 && (object == null || p.obj == object)) {
735 Message n = p.next;
736 mMessages = n;
Jeff Brown9867ed72014-02-28 14:00:57 -0800737 p.recycleUnchecked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800738 p = n;
739 }
740
741 // Remove all messages after front.
742 while (p != null) {
743 Message n = p.next;
744 if (n != null) {
745 if (n.target == h && (object == null || n.obj == object)) {
746 Message nn = n.next;
Jeff Brown9867ed72014-02-28 14:00:57 -0800747 n.recycleUnchecked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800748 p.next = nn;
749 continue;
750 }
751 }
752 p = n;
753 }
754 }
755 }
Jeff Brown8b60e452013-04-18 15:17:48 -0700756
757 private void removeAllMessagesLocked() {
758 Message p = mMessages;
759 while (p != null) {
760 Message n = p.next;
Jeff Brown9867ed72014-02-28 14:00:57 -0800761 p.recycleUnchecked();
Jeff Brown8b60e452013-04-18 15:17:48 -0700762 p = n;
763 }
764 mMessages = null;
765 }
766
767 private void removeAllFutureMessagesLocked() {
768 final long now = SystemClock.uptimeMillis();
769 Message p = mMessages;
770 if (p != null) {
771 if (p.when > now) {
772 removeAllMessagesLocked();
773 } else {
774 Message n;
775 for (;;) {
776 n = p.next;
777 if (n == null) {
778 return;
779 }
780 if (n.when > now) {
781 break;
782 }
783 p = n;
784 }
785 p.next = null;
786 do {
787 p = n;
788 n = p.next;
Jeff Brown9867ed72014-02-28 14:00:57 -0800789 p.recycleUnchecked();
Jeff Brown8b60e452013-04-18 15:17:48 -0700790 } while (n != null);
791 }
792 }
793 }
Jeff Brown5182c782013-10-15 20:31:52 -0700794
Dianne Hackborncb015632017-06-14 17:30:15 -0700795 void dump(Printer pw, String prefix, Handler h) {
Jeff Brown5182c782013-10-15 20:31:52 -0700796 synchronized (this) {
797 long now = SystemClock.uptimeMillis();
798 int n = 0;
799 for (Message msg = mMessages; msg != null; msg = msg.next) {
Dianne Hackborncb015632017-06-14 17:30:15 -0700800 if (h == null || h == msg.target) {
801 pw.println(prefix + "Message " + n + ": " + msg.toString(now));
802 }
Jeff Brown5182c782013-10-15 20:31:52 -0700803 n++;
804 }
Jeff Brown6c7b41a2015-02-26 14:43:53 -0800805 pw.println(prefix + "(Total messages: " + n + ", polling=" + isPollingLocked()
Jeff Brown5182c782013-10-15 20:31:52 -0700806 + ", quitting=" + mQuitting + ")");
807 }
808 }
Jeff Brown6c7b41a2015-02-26 14:43:53 -0800809
Netta P958d0a52017-02-07 11:20:55 -0800810 void writeToProto(ProtoOutputStream proto, long fieldId) {
811 final long messageQueueToken = proto.start(fieldId);
812 synchronized (this) {
813 for (Message msg = mMessages; msg != null; msg = msg.next) {
814 msg.writeToProto(proto, MessageQueueProto.MESSAGES);
815 }
816 proto.write(MessageQueueProto.IS_POLLING_LOCKED, isPollingLocked());
817 proto.write(MessageQueueProto.IS_QUITTING, mQuitting);
818 }
819 proto.end(messageQueueToken);
820 }
821
Jeff Brown6c7b41a2015-02-26 14:43:53 -0800822 /**
823 * Callback interface for discovering when a thread is going to block
824 * waiting for more messages.
825 */
826 public static interface IdleHandler {
827 /**
828 * Called when the message queue has run out of messages and will now
829 * wait for more. Return true to keep your idle handler active, false
830 * to have it removed. This may be called if there are still messages
831 * pending in the queue, but they are all scheduled to be dispatched
832 * after the current time.
833 */
834 boolean queueIdle();
835 }
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800836
837 /**
Jeff Brown3f640522015-05-15 12:26:15 -0700838 * A listener which is invoked when file descriptor related events occur.
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800839 */
Jeff Brown3f640522015-05-15 12:26:15 -0700840 public interface OnFileDescriptorEventListener {
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800841 /**
842 * File descriptor event: Indicates that the file descriptor is ready for input
843 * operations, such as reading.
844 * <p>
Jeff Brown3f640522015-05-15 12:26:15 -0700845 * The listener should read all available data from the file descriptor
846 * then return <code>true</code> to keep the listener active or <code>false</code>
847 * to remove the listener.
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800848 * </p><p>
849 * In the case of a socket, this event may be generated to indicate
Jeff Brown3f640522015-05-15 12:26:15 -0700850 * that there is at least one incoming connection that the listener
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800851 * should accept.
852 * </p><p>
853 * This event will only be generated if the {@link #EVENT_INPUT} 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_INPUT = 1 << 0;
858
859 /**
860 * File descriptor event: Indicates that the file descriptor is ready for output
861 * operations, such as writing.
862 * <p>
Jeff Brown3f640522015-05-15 12:26:15 -0700863 * The listener should write as much data as it needs. If it could not
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800864 * write everything at once, then it should return <code>true</code> to
Jeff Brown3f640522015-05-15 12:26:15 -0700865 * keep the listener active. Otherwise, it should return <code>false</code>
866 * to remove the listener then re-register it later when it needs to write
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800867 * something else.
868 * </p><p>
869 * This event will only be generated if the {@link #EVENT_OUTPUT} event mask was
Jeff Brown3f640522015-05-15 12:26:15 -0700870 * specified when the listener was added.
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800871 * </p>
872 */
873 public static final int EVENT_OUTPUT = 1 << 1;
874
875 /**
876 * File descriptor event: Indicates that the file descriptor encountered a
877 * fatal error.
878 * <p>
879 * File descriptor errors can occur for various reasons. One common error
880 * is when the remote peer of a socket or pipe closes its end of the connection.
881 * </p><p>
882 * This event may be generated at any time regardless of whether the
Jeff Brown3f640522015-05-15 12:26:15 -0700883 * {@link #EVENT_ERROR} event mask was specified when the listener was added.
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800884 * </p>
885 */
886 public static final int EVENT_ERROR = 1 << 2;
887
888 /** @hide */
889 @Retention(RetentionPolicy.SOURCE)
Jeff Sharkeyce8db992017-12-13 20:05:05 -0700890 @IntDef(flag = true, prefix = { "EVENT_" }, value = {
891 EVENT_INPUT,
892 EVENT_OUTPUT,
893 EVENT_ERROR
894 })
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800895 public @interface Events {}
896
897 /**
898 * Called when a file descriptor receives events.
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800899 *
900 * @param fd The file descriptor.
901 * @param events The set of events that occurred: a combination of the
902 * {@link #EVENT_INPUT}, {@link #EVENT_OUTPUT}, and {@link #EVENT_ERROR} event masks.
Jeff Brown3f640522015-05-15 12:26:15 -0700903 * @return The new set of events to watch, or 0 to unregister the listener.
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800904 *
905 * @see #EVENT_INPUT
906 * @see #EVENT_OUTPUT
907 * @see #EVENT_ERROR
908 */
Jeff Brown3f640522015-05-15 12:26:15 -0700909 @Events int onFileDescriptorEvents(@NonNull FileDescriptor fd, @Events int events);
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800910 }
911
912 private static final class FileDescriptorRecord {
913 public final FileDescriptor mDescriptor;
914 public int mEvents;
Jeff Brown3f640522015-05-15 12:26:15 -0700915 public OnFileDescriptorEventListener mListener;
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800916 public int mSeq;
917
918 public FileDescriptorRecord(FileDescriptor descriptor,
Jeff Brown3f640522015-05-15 12:26:15 -0700919 int events, OnFileDescriptorEventListener listener) {
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800920 mDescriptor = descriptor;
921 mEvents = events;
Jeff Brown3f640522015-05-15 12:26:15 -0700922 mListener = listener;
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800923 }
924 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800925}