blob: 183ef8b281ee9524b6e919f9d40e5db27efb0a47 [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;
Andrei Oneadcb67732019-03-18 11:37:25 +000021import android.annotation.UnsupportedAppUsage;
Netta P958d0a52017-02-07 11:20:55 -080022import android.os.MessageQueueProto;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080023import android.util.Log;
Jeff Brown5182c782013-10-15 20:31:52 -070024import android.util.Printer;
Jeff Browndc3eb4b2015-03-05 18:21:06 -080025import android.util.SparseArray;
Netta P958d0a52017-02-07 11:20:55 -080026import android.util.proto.ProtoOutputStream;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080027
Jeff Browndc3eb4b2015-03-05 18:21:06 -080028import java.io.FileDescriptor;
29import java.lang.annotation.Retention;
30import java.lang.annotation.RetentionPolicy;
Jeff Brown46b9ac02010-04-22 18:58:52 -070031import java.util.ArrayList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080032
33/**
34 * Low-level class holding the list of messages to be dispatched by a
35 * {@link Looper}. Messages are not added directly to a MessageQueue,
36 * but rather through {@link Handler} objects associated with the Looper.
Netta P958d0a52017-02-07 11:20:55 -080037 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038 * <p>You can retrieve the MessageQueue for the current thread with
39 * {@link Looper#myQueue() Looper.myQueue()}.
40 */
Jeff Brown67fc67c2013-04-01 13:00:33 -070041public final class MessageQueue {
Jeff Browndc3eb4b2015-03-05 18:21:06 -080042 private static final String TAG = "MessageQueue";
43 private static final boolean DEBUG = false;
44
Jeff Brown0f85ce32012-02-16 14:41:10 -080045 // True if the message queue can be quit.
Andrei Oneadcb67732019-03-18 11:37:25 +000046 @UnsupportedAppUsage
Jeff Brown0f85ce32012-02-16 14:41:10 -080047 private final boolean mQuitAllowed;
48
Andrei Oneadcb67732019-03-18 11:37:25 +000049 @UnsupportedAppUsage
Jeff Brown0f85ce32012-02-16 14:41:10 -080050 @SuppressWarnings("unused")
Ashok Bhat63a37152014-01-10 14:15:21 +000051 private long mPtr; // used by native code
Jeff Brown0f85ce32012-02-16 14:41:10 -080052
Andrei Oneadcb67732019-03-18 11:37:25 +000053 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080054 Message mMessages;
Andrei Oneadcb67732019-03-18 11:37:25 +000055 @UnsupportedAppUsage
Jeff Brown46b9ac02010-04-22 18:58:52 -070056 private final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<IdleHandler>();
Jeff Browndc3eb4b2015-03-05 18:21:06 -080057 private SparseArray<FileDescriptorRecord> mFileDescriptorRecords;
Jeff Browned739322010-09-21 15:14:14 -070058 private IdleHandler[] mPendingIdleHandlers;
Jeff Brown013cf842013-09-06 16:24:36 -070059 private boolean mQuitting;
Christopher Tatefa9e7c02010-05-06 12:07:10 -070060
Jeff Brown415d8c32010-10-05 15:35:37 -070061 // Indicates whether next() is blocked waiting in pollOnce() with a non-zero timeout.
62 private boolean mBlocked;
63
Jeff Brown0f85ce32012-02-16 14:41:10 -080064 // The next barrier token.
65 // Barriers are indicated by messages with a null target whose arg1 field carries the token.
Andrei Oneadcb67732019-03-18 11:37:25 +000066 @UnsupportedAppUsage
Jeff Brown0f85ce32012-02-16 14:41:10 -080067 private int mNextBarrierToken;
Jeff Browne799cb72012-02-14 11:53:33 -080068
Ashok Bhat63a37152014-01-10 14:15:21 +000069 private native static long nativeInit();
70 private native static void nativeDestroy(long ptr);
Andrei Oneadcb67732019-03-18 11:37:25 +000071 @UnsupportedAppUsage
Jeff Browndc3eb4b2015-03-05 18:21:06 -080072 private native void nativePollOnce(long ptr, int timeoutMillis); /*non-static for callbacks*/
Ashok Bhat63a37152014-01-10 14:15:21 +000073 private native static void nativeWake(long ptr);
Jeff Brown6c7b41a2015-02-26 14:43:53 -080074 private native static boolean nativeIsPolling(long ptr);
Jeff Browndc3eb4b2015-03-05 18:21:06 -080075 private native static void nativeSetFileDescriptorEvents(long ptr, int fd, int events);
Jeff Browne799cb72012-02-14 11:53:33 -080076
Jeff Brown0f85ce32012-02-16 14:41:10 -080077 MessageQueue(boolean quitAllowed) {
78 mQuitAllowed = quitAllowed;
Jeff Brown864693462013-01-28 14:25:53 -080079 mPtr = nativeInit();
Christopher Tatefa9e7c02010-05-06 12:07:10 -070080 }
Jeff Brown0f85ce32012-02-16 14:41:10 -080081
Jeff Brown46b9ac02010-04-22 18:58:52 -070082 @Override
83 protected void finalize() throws Throwable {
84 try {
Jeff Brown864693462013-01-28 14:25:53 -080085 dispose();
Jeff Brown46b9ac02010-04-22 18:58:52 -070086 } finally {
87 super.finalize();
88 }
89 }
Christopher Tatefa9e7c02010-05-06 12:07:10 -070090
Jeff Brown013cf842013-09-06 16:24:36 -070091 // Disposes of the underlying message queue.
92 // Must only be called on the looper thread or the finalizer.
Jeff Brown864693462013-01-28 14:25:53 -080093 private void dispose() {
94 if (mPtr != 0) {
95 nativeDestroy(mPtr);
96 mPtr = 0;
97 }
98 }
99
Jeff Brown6c7b41a2015-02-26 14:43:53 -0800100 /**
101 * Returns true if the looper has no pending messages which are due to be processed.
102 *
103 * <p>This method is safe to call from any thread.
104 *
105 * @return True if the looper is idle.
106 */
107 public boolean isIdle() {
108 synchronized (this) {
109 final long now = SystemClock.uptimeMillis();
110 return mMessages == null || now < mMessages.when;
111 }
112 }
113
114 /**
115 * Add a new {@link IdleHandler} to this message queue. This may be
116 * removed automatically for you by returning false from
117 * {@link IdleHandler#queueIdle IdleHandler.queueIdle()} when it is
118 * invoked, or explicitly removing it with {@link #removeIdleHandler}.
119 *
120 * <p>This method is safe to call from any thread.
121 *
122 * @param handler The IdleHandler to be added.
123 */
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800124 public void addIdleHandler(@NonNull IdleHandler handler) {
Jeff Brown6c7b41a2015-02-26 14:43:53 -0800125 if (handler == null) {
126 throw new NullPointerException("Can't add a null IdleHandler");
127 }
128 synchronized (this) {
129 mIdleHandlers.add(handler);
130 }
131 }
132
133 /**
134 * Remove an {@link IdleHandler} from the queue that was previously added
135 * with {@link #addIdleHandler}. If the given object is not currently
136 * in the idle list, nothing is done.
137 *
138 * <p>This method is safe to call from any thread.
139 *
140 * @param handler The IdleHandler to be removed.
141 */
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800142 public void removeIdleHandler(@NonNull IdleHandler handler) {
Jeff Brown6c7b41a2015-02-26 14:43:53 -0800143 synchronized (this) {
144 mIdleHandlers.remove(handler);
145 }
146 }
147
148 /**
149 * Returns whether this looper's thread is currently polling for more work to do.
150 * This is a good signal that the loop is still alive rather than being stuck
151 * handling a callback. Note that this method is intrinsically racy, since the
152 * state of the loop can change before you get the result back.
153 *
154 * <p>This method is safe to call from any thread.
155 *
156 * @return True if the looper is currently polling for events.
157 * @hide
158 */
159 public boolean isPolling() {
160 synchronized (this) {
161 return isPollingLocked();
162 }
163 }
164
165 private boolean isPollingLocked() {
166 // If the loop is quitting then it must not be idling.
167 // We can assume mPtr != 0 when mQuitting is false.
168 return !mQuitting && nativeIsPolling(mPtr);
169 }
170
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800171 /**
Jeff Brown3f640522015-05-15 12:26:15 -0700172 * Adds a file descriptor listener to receive notification when file descriptor
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800173 * related events occur.
174 * <p>
175 * If the file descriptor has already been registered, the specified events
Jeff Brown3f640522015-05-15 12:26:15 -0700176 * and listener will replace any that were previously associated with it.
177 * It is not possible to set more than one listener per file descriptor.
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800178 * </p><p>
Jeff Brown3f640522015-05-15 12:26:15 -0700179 * It is important to always unregister the listener when the file descriptor
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800180 * is no longer of use.
181 * </p>
182 *
Jeff Brown3f640522015-05-15 12:26:15 -0700183 * @param fd The file descriptor for which a listener will be registered.
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800184 * @param events The set of events to receive: a combination of the
Jeff Brown3f640522015-05-15 12:26:15 -0700185 * {@link OnFileDescriptorEventListener#EVENT_INPUT},
186 * {@link OnFileDescriptorEventListener#EVENT_OUTPUT}, and
187 * {@link OnFileDescriptorEventListener#EVENT_ERROR} event masks. If the requested
188 * set of events is zero, then the listener is unregistered.
189 * @param listener The listener to invoke when file descriptor events occur.
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800190 *
Jeff Brown3f640522015-05-15 12:26:15 -0700191 * @see OnFileDescriptorEventListener
192 * @see #removeOnFileDescriptorEventListener
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800193 */
Jeff Brown3f640522015-05-15 12:26:15 -0700194 public void addOnFileDescriptorEventListener(@NonNull FileDescriptor fd,
195 @OnFileDescriptorEventListener.Events int events,
196 @NonNull OnFileDescriptorEventListener listener) {
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800197 if (fd == null) {
198 throw new IllegalArgumentException("fd must not be null");
199 }
Jeff Brown3f640522015-05-15 12:26:15 -0700200 if (listener == null) {
201 throw new IllegalArgumentException("listener must not be null");
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800202 }
203
204 synchronized (this) {
Jeff Brown3f640522015-05-15 12:26:15 -0700205 updateOnFileDescriptorEventListenerLocked(fd, events, listener);
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800206 }
207 }
208
209 /**
Jeff Brown3f640522015-05-15 12:26:15 -0700210 * Removes a file descriptor listener.
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800211 * <p>
Jeff Brown3f640522015-05-15 12:26:15 -0700212 * This method does nothing if no listener has been registered for the
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800213 * specified file descriptor.
214 * </p>
215 *
Jeff Brown3f640522015-05-15 12:26:15 -0700216 * @param fd The file descriptor whose listener will be unregistered.
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800217 *
Jeff Brown3f640522015-05-15 12:26:15 -0700218 * @see OnFileDescriptorEventListener
219 * @see #addOnFileDescriptorEventListener
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800220 */
Jeff Brown3f640522015-05-15 12:26:15 -0700221 public void removeOnFileDescriptorEventListener(@NonNull FileDescriptor fd) {
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800222 if (fd == null) {
223 throw new IllegalArgumentException("fd must not be null");
224 }
225
226 synchronized (this) {
Jeff Brown3f640522015-05-15 12:26:15 -0700227 updateOnFileDescriptorEventListenerLocked(fd, 0, null);
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800228 }
229 }
230
Jeff Brown3f640522015-05-15 12:26:15 -0700231 private void updateOnFileDescriptorEventListenerLocked(FileDescriptor fd, int events,
232 OnFileDescriptorEventListener listener) {
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800233 final int fdNum = fd.getInt$();
234
235 int index = -1;
236 FileDescriptorRecord record = null;
237 if (mFileDescriptorRecords != null) {
238 index = mFileDescriptorRecords.indexOfKey(fdNum);
239 if (index >= 0) {
240 record = mFileDescriptorRecords.valueAt(index);
241 if (record != null && record.mEvents == events) {
242 return;
243 }
244 }
245 }
246
247 if (events != 0) {
Jeff Brown3f640522015-05-15 12:26:15 -0700248 events |= OnFileDescriptorEventListener.EVENT_ERROR;
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800249 if (record == null) {
250 if (mFileDescriptorRecords == null) {
251 mFileDescriptorRecords = new SparseArray<FileDescriptorRecord>();
252 }
Jeff Brown3f640522015-05-15 12:26:15 -0700253 record = new FileDescriptorRecord(fd, events, listener);
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800254 mFileDescriptorRecords.put(fdNum, record);
255 } else {
Jeff Brown3f640522015-05-15 12:26:15 -0700256 record.mListener = listener;
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800257 record.mEvents = events;
258 record.mSeq += 1;
259 }
260 nativeSetFileDescriptorEvents(mPtr, fdNum, events);
261 } else if (record != null) {
262 record.mEvents = 0;
263 mFileDescriptorRecords.removeAt(index);
David Pursellc16b7752017-08-07 16:32:36 -0700264 nativeSetFileDescriptorEvents(mPtr, fdNum, 0);
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800265 }
266 }
267
268 // Called from native code.
Andrei Oneadcb67732019-03-18 11:37:25 +0000269 @UnsupportedAppUsage
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800270 private int dispatchEvents(int fd, int events) {
271 // Get the file descriptor record and any state that might change.
272 final FileDescriptorRecord record;
273 final int oldWatchedEvents;
Jeff Brown3f640522015-05-15 12:26:15 -0700274 final OnFileDescriptorEventListener listener;
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800275 final int seq;
276 synchronized (this) {
277 record = mFileDescriptorRecords.get(fd);
278 if (record == null) {
Jeff Brown3f640522015-05-15 12:26:15 -0700279 return 0; // spurious, no listener registered
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800280 }
281
282 oldWatchedEvents = record.mEvents;
283 events &= oldWatchedEvents; // filter events based on current watched set
284 if (events == 0) {
285 return oldWatchedEvents; // spurious, watched events changed
286 }
287
Jeff Brown3f640522015-05-15 12:26:15 -0700288 listener = record.mListener;
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800289 seq = record.mSeq;
290 }
291
Jeff Brown3f640522015-05-15 12:26:15 -0700292 // Invoke the listener outside of the lock.
293 int newWatchedEvents = listener.onFileDescriptorEvents(
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800294 record.mDescriptor, events);
295 if (newWatchedEvents != 0) {
Jeff Brown3f640522015-05-15 12:26:15 -0700296 newWatchedEvents |= OnFileDescriptorEventListener.EVENT_ERROR;
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800297 }
298
Jeff Brown3f640522015-05-15 12:26:15 -0700299 // Update the file descriptor record if the listener changed the set of
300 // events to watch and the listener itself hasn't been updated since.
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800301 if (newWatchedEvents != oldWatchedEvents) {
302 synchronized (this) {
303 int index = mFileDescriptorRecords.indexOfKey(fd);
304 if (index >= 0 && mFileDescriptorRecords.valueAt(index) == record
305 && record.mSeq == seq) {
306 record.mEvents = newWatchedEvents;
307 if (newWatchedEvents == 0) {
308 mFileDescriptorRecords.removeAt(index);
309 }
310 }
311 }
312 }
313
314 // Return the new set of events to watch for native code to take care of.
315 return newWatchedEvents;
316 }
317
Andrei Oneadcb67732019-03-18 11:37:25 +0000318 @UnsupportedAppUsage
Jeff Brown67fc67c2013-04-01 13:00:33 -0700319 Message next() {
Jeff Brown60583902013-09-09 16:14:20 -0700320 // Return here if the message loop has already quit and been disposed.
321 // This can happen if the application tries to restart a looper after quit
322 // which is not supported.
Narayan Kamathab864342014-01-16 11:22:52 +0000323 final long ptr = mPtr;
Jeff Brown60583902013-09-09 16:14:20 -0700324 if (ptr == 0) {
325 return null;
326 }
327
Jeff Browned739322010-09-21 15:14:14 -0700328 int pendingIdleHandlerCount = -1; // -1 only during first iteration
329 int nextPollTimeoutMillis = 0;
Jeff Browned739322010-09-21 15:14:14 -0700330 for (;;) {
331 if (nextPollTimeoutMillis != 0) {
332 Binder.flushPendingCommands();
333 }
Jeff Brown013cf842013-09-06 16:24:36 -0700334
Jeff Brown60583902013-09-09 16:14:20 -0700335 nativePollOnce(ptr, nextPollTimeoutMillis);
Christopher Tatefa9e7c02010-05-06 12:07:10 -0700336
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800337 synchronized (this) {
Jeff Browned739322010-09-21 15:14:14 -0700338 // Try to retrieve the next message. Return if found.
339 final long now = SystemClock.uptimeMillis();
Jeff Browne799cb72012-02-14 11:53:33 -0800340 Message prevMsg = null;
341 Message msg = mMessages;
Jeff Brown0f85ce32012-02-16 14:41:10 -0800342 if (msg != null && msg.target == null) {
343 // Stalled by a barrier. Find the next asynchronous message in the queue.
344 do {
345 prevMsg = msg;
346 msg = msg.next;
347 } while (msg != null && !msg.isAsynchronous());
348 }
349 if (msg != null) {
350 if (now < msg.when) {
Jeff Browne799cb72012-02-14 11:53:33 -0800351 // Next message is not ready. Set a timeout to wake up when it is ready.
Jeff Brown0f85ce32012-02-16 14:41:10 -0800352 nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
353 } else {
Jeff Browne799cb72012-02-14 11:53:33 -0800354 // Got a message.
Jeff Brown415d8c32010-10-05 15:35:37 -0700355 mBlocked = false;
Jeff Browne799cb72012-02-14 11:53:33 -0800356 if (prevMsg != null) {
357 prevMsg.next = msg.next;
358 } else {
359 mMessages = msg.next;
360 }
Jeff Brown415d8c32010-10-05 15:35:37 -0700361 msg.next = null;
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800362 if (DEBUG) Log.v(TAG, "Returning message: " + msg);
363 msg.markInUse();
Jeff Browned739322010-09-21 15:14:14 -0700364 return msg;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800365 }
Jeff Brown0f85ce32012-02-16 14:41:10 -0800366 } else {
367 // No more messages.
368 nextPollTimeoutMillis = -1;
Jeff Browned739322010-09-21 15:14:14 -0700369 }
370
Jeff Brown024136f2013-04-11 19:21:32 -0700371 // Process the quit message now that all pending messages have been handled.
Jeff Brown013cf842013-09-06 16:24:36 -0700372 if (mQuitting) {
Jeff Brown024136f2013-04-11 19:21:32 -0700373 dispose();
374 return null;
375 }
376
Jeff Browne799cb72012-02-14 11:53:33 -0800377 // If first time idle, then get the number of idlers to run.
Jeff Brown0f85ce32012-02-16 14:41:10 -0800378 // Idle handles only run if the queue is empty or if the first message
379 // in the queue (possibly a barrier) is due to be handled in the future.
380 if (pendingIdleHandlerCount < 0
381 && (mMessages == null || now < mMessages.when)) {
Jeff Browned739322010-09-21 15:14:14 -0700382 pendingIdleHandlerCount = mIdleHandlers.size();
383 }
Jeff Browne799cb72012-02-14 11:53:33 -0800384 if (pendingIdleHandlerCount <= 0) {
Jeff Browned739322010-09-21 15:14:14 -0700385 // No idle handlers to run. Loop and wait some more.
Jeff Brown415d8c32010-10-05 15:35:37 -0700386 mBlocked = true;
Jeff Browned739322010-09-21 15:14:14 -0700387 continue;
388 }
389
390 if (mPendingIdleHandlers == null) {
391 mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
392 }
393 mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
394 }
395
396 // Run the idle handlers.
397 // We only ever reach this code block during the first iteration.
398 for (int i = 0; i < pendingIdleHandlerCount; i++) {
399 final IdleHandler idler = mPendingIdleHandlers[i];
400 mPendingIdleHandlers[i] = null; // release the reference to the handler
401
402 boolean keep = false;
403 try {
404 keep = idler.queueIdle();
405 } catch (Throwable t) {
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800406 Log.wtf(TAG, "IdleHandler threw exception", t);
Jeff Browned739322010-09-21 15:14:14 -0700407 }
408
409 if (!keep) {
410 synchronized (this) {
411 mIdleHandlers.remove(idler);
412 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800413 }
414 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800415
Jeff Browned739322010-09-21 15:14:14 -0700416 // Reset the idle handler count to 0 so we do not run them again.
417 pendingIdleHandlerCount = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800418
Jeff Browned739322010-09-21 15:14:14 -0700419 // While calling an idle handler, a new message could have been delivered
420 // so go back and look again for a pending message without waiting.
421 nextPollTimeoutMillis = 0;
422 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800423 }
424
Jeff Brown8b60e452013-04-18 15:17:48 -0700425 void quit(boolean safe) {
Jeff Brown0f85ce32012-02-16 14:41:10 -0800426 if (!mQuitAllowed) {
Jeff Brown9867ed72014-02-28 14:00:57 -0800427 throw new IllegalStateException("Main thread not allowed to quit.");
Jeff Brown0f85ce32012-02-16 14:41:10 -0800428 }
429
430 synchronized (this) {
Jeff Brown013cf842013-09-06 16:24:36 -0700431 if (mQuitting) {
Jeff Brown0f85ce32012-02-16 14:41:10 -0800432 return;
433 }
Jeff Brown013cf842013-09-06 16:24:36 -0700434 mQuitting = true;
Jeff Brown8b60e452013-04-18 15:17:48 -0700435
436 if (safe) {
437 removeAllFutureMessagesLocked();
438 } else {
439 removeAllMessagesLocked();
440 }
Jeff Brown013cf842013-09-06 16:24:36 -0700441
442 // We can assume mPtr != 0 because mQuitting was previously false.
443 nativeWake(mPtr);
Jeff Brown0f85ce32012-02-16 14:41:10 -0800444 }
Jeff Brown0f85ce32012-02-16 14:41:10 -0800445 }
446
Jeff Brown3d4e7efe2015-02-26 15:34:16 -0800447 /**
448 * Posts a synchronization barrier to the Looper's message queue.
449 *
450 * Message processing occurs as usual until the message queue encounters the
451 * synchronization barrier that has been posted. When the barrier is encountered,
452 * later synchronous messages in the queue are stalled (prevented from being executed)
453 * until the barrier is released by calling {@link #removeSyncBarrier} and specifying
454 * the token that identifies the synchronization barrier.
455 *
456 * This method is used to immediately postpone execution of all subsequently posted
457 * synchronous messages until a condition is met that releases the barrier.
458 * Asynchronous messages (see {@link Message#isAsynchronous} are exempt from the barrier
459 * and continue to be processed as usual.
460 *
461 * This call must be always matched by a call to {@link #removeSyncBarrier} with
462 * the same token to ensure that the message queue resumes normal operation.
463 * Otherwise the application will probably hang!
464 *
465 * @return A token that uniquely identifies the barrier. This token must be
466 * passed to {@link #removeSyncBarrier} to release the barrier.
467 *
468 * @hide
469 */
Andrei Oneadcb67732019-03-18 11:37:25 +0000470 @UnsupportedAppUsage
Jeff Brown3d4e7efe2015-02-26 15:34:16 -0800471 public int postSyncBarrier() {
472 return postSyncBarrier(SystemClock.uptimeMillis());
473 }
474
475 private int postSyncBarrier(long when) {
Jeff Brown0f85ce32012-02-16 14:41:10 -0800476 // Enqueue a new sync barrier token.
477 // We don't need to wake the queue because the purpose of a barrier is to stall it.
478 synchronized (this) {
479 final int token = mNextBarrierToken++;
480 final Message msg = Message.obtain();
Jeff Brown9867ed72014-02-28 14:00:57 -0800481 msg.markInUse();
Jeff Brown5182c782013-10-15 20:31:52 -0700482 msg.when = when;
Jeff Brown0f85ce32012-02-16 14:41:10 -0800483 msg.arg1 = token;
484
485 Message prev = null;
486 Message p = mMessages;
487 if (when != 0) {
488 while (p != null && p.when <= when) {
489 prev = p;
490 p = p.next;
491 }
492 }
493 if (prev != null) { // invariant: p == prev.next
494 msg.next = p;
495 prev.next = msg;
496 } else {
497 msg.next = p;
498 mMessages = msg;
499 }
500 return token;
501 }
502 }
503
Jeff Brown3d4e7efe2015-02-26 15:34:16 -0800504 /**
505 * Removes a synchronization barrier.
506 *
507 * @param token The synchronization barrier token that was returned by
508 * {@link #postSyncBarrier}.
509 *
510 * @throws IllegalStateException if the barrier was not found.
511 *
512 * @hide
513 */
Andrei Oneadcb67732019-03-18 11:37:25 +0000514 @UnsupportedAppUsage
Jeff Brown3d4e7efe2015-02-26 15:34:16 -0800515 public void removeSyncBarrier(int token) {
Jeff Brown0f85ce32012-02-16 14:41:10 -0800516 // Remove a sync barrier token from the queue.
517 // If the queue is no longer stalled by a barrier then wake it.
Jeff Brown0f85ce32012-02-16 14:41:10 -0800518 synchronized (this) {
519 Message prev = null;
520 Message p = mMessages;
521 while (p != null && (p.target != null || p.arg1 != token)) {
522 prev = p;
523 p = p.next;
524 }
525 if (p == null) {
526 throw new IllegalStateException("The specified message queue synchronization "
527 + " barrier token has not been posted or has already been removed.");
528 }
Jeff Brown013cf842013-09-06 16:24:36 -0700529 final boolean needWake;
Jeff Brown0f85ce32012-02-16 14:41:10 -0800530 if (prev != null) {
531 prev.next = p.next;
532 needWake = false;
533 } else {
534 mMessages = p.next;
535 needWake = mMessages == null || mMessages.target != null;
536 }
Jeff Brown9867ed72014-02-28 14:00:57 -0800537 p.recycleUnchecked();
Jeff Brown013cf842013-09-06 16:24:36 -0700538
539 // If the loop is quitting then it is already awake.
540 // We can assume mPtr != 0 when mQuitting is false.
541 if (needWake && !mQuitting) {
542 nativeWake(mPtr);
543 }
Jeff Brown0f85ce32012-02-16 14:41:10 -0800544 }
545 }
546
Jeff Brown67fc67c2013-04-01 13:00:33 -0700547 boolean enqueueMessage(Message msg, long when) {
Jeff Brown0f85ce32012-02-16 14:41:10 -0800548 if (msg.target == null) {
Jeff Brown9867ed72014-02-28 14:00:57 -0800549 throw new IllegalArgumentException("Message must have a target.");
550 }
551 if (msg.isInUse()) {
552 throw new IllegalStateException(msg + " This message is already in use.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800553 }
Jeff Brown0f85ce32012-02-16 14:41:10 -0800554
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800555 synchronized (this) {
Jeff Brown013cf842013-09-06 16:24:36 -0700556 if (mQuitting) {
Jeff Brown9867ed72014-02-28 14:00:57 -0800557 IllegalStateException e = new IllegalStateException(
Jeff Brown0f85ce32012-02-16 14:41:10 -0800558 msg.target + " sending message to a Handler on a dead thread");
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800559 Log.w(TAG, e.getMessage(), e);
Jeff Brown9867ed72014-02-28 14:00:57 -0800560 msg.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800561 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800562 }
563
Jeff Brown9867ed72014-02-28 14:00:57 -0800564 msg.markInUse();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800565 msg.when = when;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800566 Message p = mMessages;
Jeff Brown013cf842013-09-06 16:24:36 -0700567 boolean needWake;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800568 if (p == null || when == 0 || when < p.when) {
Jeff Browne799cb72012-02-14 11:53:33 -0800569 // New head, wake up the event queue if blocked.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800570 msg.next = p;
571 mMessages = msg;
Jeff Browne799cb72012-02-14 11:53:33 -0800572 needWake = mBlocked;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800573 } else {
Jeff Browne799cb72012-02-14 11:53:33 -0800574 // Inserted within the middle of the queue. Usually we don't have to wake
Jeff Brown0f85ce32012-02-16 14:41:10 -0800575 // up the event queue unless there is a barrier at the head of the queue
576 // and the message is the earliest asynchronous message in the queue.
577 needWake = mBlocked && p.target == null && msg.isAsynchronous();
578 Message prev;
579 for (;;) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800580 prev = p;
581 p = p.next;
Jeff Brown0f85ce32012-02-16 14:41:10 -0800582 if (p == null || when < p.when) {
583 break;
584 }
585 if (needWake && p.isAsynchronous()) {
586 needWake = false;
587 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800588 }
Jeff Brown0f85ce32012-02-16 14:41:10 -0800589 msg.next = p; // invariant: p == prev.next
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800590 prev.next = msg;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800591 }
Jeff Brown013cf842013-09-06 16:24:36 -0700592
593 // We can assume mPtr != 0 because mQuitting is false.
594 if (needWake) {
595 nativeWake(mPtr);
596 }
Jeff Brown415d8c32010-10-05 15:35:37 -0700597 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800598 return true;
599 }
600
Jeff Brown67fc67c2013-04-01 13:00:33 -0700601 boolean hasMessages(Handler h, int what, Object object) {
Jeff Brown0f85ce32012-02-16 14:41:10 -0800602 if (h == null) {
603 return false;
604 }
605
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800606 synchronized (this) {
607 Message p = mMessages;
Jeff Brown0f85ce32012-02-16 14:41:10 -0800608 while (p != null) {
609 if (p.target == h && p.what == what && (object == null || p.obj == object)) {
610 return true;
611 }
612 p = p.next;
613 }
614 return false;
615 }
616 }
617
Andrei Oneadcb67732019-03-18 11:37:25 +0000618 @UnsupportedAppUsage
Jeff Brown67fc67c2013-04-01 13:00:33 -0700619 boolean hasMessages(Handler h, Runnable r, Object object) {
Romain Guyba6be8a2012-04-23 18:22:09 -0700620 if (h == null) {
621 return false;
622 }
623
624 synchronized (this) {
625 Message p = mMessages;
626 while (p != null) {
627 if (p.target == h && p.callback == r && (object == null || p.obj == object)) {
628 return true;
629 }
630 p = p.next;
631 }
632 return false;
633 }
634 }
635
Dianne Hackborncb015632017-06-14 17:30:15 -0700636 boolean hasMessages(Handler h) {
637 if (h == null) {
638 return false;
639 }
640
641 synchronized (this) {
642 Message p = mMessages;
643 while (p != null) {
644 if (p.target == h) {
645 return true;
646 }
647 p = p.next;
648 }
649 return false;
650 }
651 }
652
Jeff Brown67fc67c2013-04-01 13:00:33 -0700653 void removeMessages(Handler h, int what, Object object) {
Jeff Brown0f85ce32012-02-16 14:41:10 -0800654 if (h == null) {
655 return;
656 }
657
658 synchronized (this) {
659 Message p = mMessages;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800660
661 // Remove all messages at front.
662 while (p != null && p.target == h && p.what == what
663 && (object == null || p.obj == object)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800664 Message n = p.next;
665 mMessages = n;
Jeff Brown9867ed72014-02-28 14:00:57 -0800666 p.recycleUnchecked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800667 p = n;
668 }
669
670 // Remove all messages after front.
671 while (p != null) {
672 Message n = p.next;
673 if (n != null) {
674 if (n.target == h && n.what == what
675 && (object == null || n.obj == object)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800676 Message nn = n.next;
Jeff Brown9867ed72014-02-28 14:00:57 -0800677 n.recycleUnchecked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800678 p.next = nn;
679 continue;
680 }
681 }
682 p = n;
683 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800684 }
685 }
686
Jeff Brown67fc67c2013-04-01 13:00:33 -0700687 void removeMessages(Handler h, Runnable r, Object object) {
Jeff Brown0f85ce32012-02-16 14:41:10 -0800688 if (h == null || r == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800689 return;
690 }
691
692 synchronized (this) {
693 Message p = mMessages;
694
695 // Remove all messages at front.
696 while (p != null && p.target == h && p.callback == r
697 && (object == null || p.obj == object)) {
698 Message n = p.next;
699 mMessages = n;
Jeff Brown9867ed72014-02-28 14:00:57 -0800700 p.recycleUnchecked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800701 p = n;
702 }
703
704 // Remove all messages after front.
705 while (p != null) {
706 Message n = p.next;
707 if (n != null) {
708 if (n.target == h && n.callback == r
709 && (object == null || n.obj == object)) {
710 Message nn = n.next;
Jeff Brown9867ed72014-02-28 14:00:57 -0800711 n.recycleUnchecked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800712 p.next = nn;
713 continue;
714 }
715 }
716 p = n;
717 }
718 }
719 }
720
Jeff Brown67fc67c2013-04-01 13:00:33 -0700721 void removeCallbacksAndMessages(Handler h, Object object) {
Jeff Brown0f85ce32012-02-16 14:41:10 -0800722 if (h == null) {
723 return;
724 }
725
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800726 synchronized (this) {
727 Message p = mMessages;
728
729 // Remove all messages at front.
730 while (p != null && p.target == h
731 && (object == null || p.obj == object)) {
732 Message n = p.next;
733 mMessages = n;
Jeff Brown9867ed72014-02-28 14:00:57 -0800734 p.recycleUnchecked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800735 p = n;
736 }
737
738 // Remove all messages after front.
739 while (p != null) {
740 Message n = p.next;
741 if (n != null) {
742 if (n.target == h && (object == null || n.obj == object)) {
743 Message nn = n.next;
Jeff Brown9867ed72014-02-28 14:00:57 -0800744 n.recycleUnchecked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800745 p.next = nn;
746 continue;
747 }
748 }
749 p = n;
750 }
751 }
752 }
Jeff Brown8b60e452013-04-18 15:17:48 -0700753
754 private void removeAllMessagesLocked() {
755 Message p = mMessages;
756 while (p != null) {
757 Message n = p.next;
Jeff Brown9867ed72014-02-28 14:00:57 -0800758 p.recycleUnchecked();
Jeff Brown8b60e452013-04-18 15:17:48 -0700759 p = n;
760 }
761 mMessages = null;
762 }
763
764 private void removeAllFutureMessagesLocked() {
765 final long now = SystemClock.uptimeMillis();
766 Message p = mMessages;
767 if (p != null) {
768 if (p.when > now) {
769 removeAllMessagesLocked();
770 } else {
771 Message n;
772 for (;;) {
773 n = p.next;
774 if (n == null) {
775 return;
776 }
777 if (n.when > now) {
778 break;
779 }
780 p = n;
781 }
782 p.next = null;
783 do {
784 p = n;
785 n = p.next;
Jeff Brown9867ed72014-02-28 14:00:57 -0800786 p.recycleUnchecked();
Jeff Brown8b60e452013-04-18 15:17:48 -0700787 } while (n != null);
788 }
789 }
790 }
Jeff Brown5182c782013-10-15 20:31:52 -0700791
Dianne Hackborncb015632017-06-14 17:30:15 -0700792 void dump(Printer pw, String prefix, Handler h) {
Jeff Brown5182c782013-10-15 20:31:52 -0700793 synchronized (this) {
794 long now = SystemClock.uptimeMillis();
795 int n = 0;
796 for (Message msg = mMessages; msg != null; msg = msg.next) {
Dianne Hackborncb015632017-06-14 17:30:15 -0700797 if (h == null || h == msg.target) {
798 pw.println(prefix + "Message " + n + ": " + msg.toString(now));
799 }
Jeff Brown5182c782013-10-15 20:31:52 -0700800 n++;
801 }
Jeff Brown6c7b41a2015-02-26 14:43:53 -0800802 pw.println(prefix + "(Total messages: " + n + ", polling=" + isPollingLocked()
Jeff Brown5182c782013-10-15 20:31:52 -0700803 + ", quitting=" + mQuitting + ")");
804 }
805 }
Jeff Brown6c7b41a2015-02-26 14:43:53 -0800806
Netta P958d0a52017-02-07 11:20:55 -0800807 void writeToProto(ProtoOutputStream proto, long fieldId) {
808 final long messageQueueToken = proto.start(fieldId);
809 synchronized (this) {
810 for (Message msg = mMessages; msg != null; msg = msg.next) {
811 msg.writeToProto(proto, MessageQueueProto.MESSAGES);
812 }
813 proto.write(MessageQueueProto.IS_POLLING_LOCKED, isPollingLocked());
814 proto.write(MessageQueueProto.IS_QUITTING, mQuitting);
815 }
816 proto.end(messageQueueToken);
817 }
818
Jeff Brown6c7b41a2015-02-26 14:43:53 -0800819 /**
820 * Callback interface for discovering when a thread is going to block
821 * waiting for more messages.
822 */
823 public static interface IdleHandler {
824 /**
825 * Called when the message queue has run out of messages and will now
826 * wait for more. Return true to keep your idle handler active, false
827 * to have it removed. This may be called if there are still messages
828 * pending in the queue, but they are all scheduled to be dispatched
829 * after the current time.
830 */
831 boolean queueIdle();
832 }
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800833
834 /**
Jeff Brown3f640522015-05-15 12:26:15 -0700835 * A listener which is invoked when file descriptor related events occur.
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800836 */
Jeff Brown3f640522015-05-15 12:26:15 -0700837 public interface OnFileDescriptorEventListener {
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800838 /**
839 * File descriptor event: Indicates that the file descriptor is ready for input
840 * operations, such as reading.
841 * <p>
Jeff Brown3f640522015-05-15 12:26:15 -0700842 * The listener should read all available data from the file descriptor
843 * then return <code>true</code> to keep the listener active or <code>false</code>
844 * to remove the listener.
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800845 * </p><p>
846 * In the case of a socket, this event may be generated to indicate
Jeff Brown3f640522015-05-15 12:26:15 -0700847 * that there is at least one incoming connection that the listener
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800848 * should accept.
849 * </p><p>
850 * This event will only be generated if the {@link #EVENT_INPUT} event mask was
Jeff Brown3f640522015-05-15 12:26:15 -0700851 * specified when the listener was added.
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800852 * </p>
853 */
854 public static final int EVENT_INPUT = 1 << 0;
855
856 /**
857 * File descriptor event: Indicates that the file descriptor is ready for output
858 * operations, such as writing.
859 * <p>
Jeff Brown3f640522015-05-15 12:26:15 -0700860 * The listener should write as much data as it needs. If it could not
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800861 * write everything at once, then it should return <code>true</code> to
Jeff Brown3f640522015-05-15 12:26:15 -0700862 * keep the listener active. Otherwise, it should return <code>false</code>
863 * to remove the listener then re-register it later when it needs to write
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800864 * something else.
865 * </p><p>
866 * This event will only be generated if the {@link #EVENT_OUTPUT} event mask was
Jeff Brown3f640522015-05-15 12:26:15 -0700867 * specified when the listener was added.
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800868 * </p>
869 */
870 public static final int EVENT_OUTPUT = 1 << 1;
871
872 /**
873 * File descriptor event: Indicates that the file descriptor encountered a
874 * fatal error.
875 * <p>
876 * File descriptor errors can occur for various reasons. One common error
877 * is when the remote peer of a socket or pipe closes its end of the connection.
878 * </p><p>
879 * This event may be generated at any time regardless of whether the
Jeff Brown3f640522015-05-15 12:26:15 -0700880 * {@link #EVENT_ERROR} event mask was specified when the listener was added.
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800881 * </p>
882 */
883 public static final int EVENT_ERROR = 1 << 2;
884
885 /** @hide */
886 @Retention(RetentionPolicy.SOURCE)
Jeff Sharkeyce8db992017-12-13 20:05:05 -0700887 @IntDef(flag = true, prefix = { "EVENT_" }, value = {
888 EVENT_INPUT,
889 EVENT_OUTPUT,
890 EVENT_ERROR
891 })
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800892 public @interface Events {}
893
894 /**
895 * Called when a file descriptor receives events.
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800896 *
897 * @param fd The file descriptor.
898 * @param events The set of events that occurred: a combination of the
899 * {@link #EVENT_INPUT}, {@link #EVENT_OUTPUT}, and {@link #EVENT_ERROR} event masks.
Jeff Brown3f640522015-05-15 12:26:15 -0700900 * @return The new set of events to watch, or 0 to unregister the listener.
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800901 *
902 * @see #EVENT_INPUT
903 * @see #EVENT_OUTPUT
904 * @see #EVENT_ERROR
905 */
Jeff Brown3f640522015-05-15 12:26:15 -0700906 @Events int onFileDescriptorEvents(@NonNull FileDescriptor fd, @Events int events);
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800907 }
908
909 private static final class FileDescriptorRecord {
910 public final FileDescriptor mDescriptor;
911 public int mEvents;
Jeff Brown3f640522015-05-15 12:26:15 -0700912 public OnFileDescriptorEventListener mListener;
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800913 public int mSeq;
914
915 public FileDescriptorRecord(FileDescriptor descriptor,
Jeff Brown3f640522015-05-15 12:26:15 -0700916 int events, OnFileDescriptorEventListener listener) {
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800917 mDescriptor = descriptor;
918 mEvents = events;
Jeff Brown3f640522015-05-15 12:26:15 -0700919 mListener = listener;
Jeff Browndc3eb4b2015-03-05 18:21:06 -0800920 }
921 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800922}