Android 17 的无锁 MessageQueue

Android 17 以下 MessageQueue 线程锁

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
/*
* Copyright (C) 2006 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package android.os;

import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.annotation.TestApi;
import android.app.ActivityThread;
import android.app.Instrumentation;
import android.compat.annotation.UnsupportedAppUsage;
import android.ravenwood.annotation.RavenwoodKeepWholeClass;
import android.ravenwood.annotation.RavenwoodRedirect;
import android.ravenwood.annotation.RavenwoodRedirectionClass;
import android.util.Log;
import android.util.Printer;
import android.util.SparseArray;
import android.util.proto.ProtoOutputStream;

import dalvik.annotation.optimization.NeverCompile;

import java.io.FileDescriptor;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicLong;

/**
* Low-level class holding the list of messages to be dispatched by a
* {@link Looper}. Messages are not added directly to a MessageQueue,
* but rather through {@link Handler} objects associated with the Looper.
*
* <p>You can retrieve the MessageQueue for the current thread with
* {@link Looper#myQueue() Looper.myQueue()}.
*/
@RavenwoodKeepWholeClass
@RavenwoodRedirectionClass("MessageQueue_ravenwood")
public final class MessageQueue {
private static final String TAG = "MessageQueue";
private static final boolean DEBUG = false;
private static final boolean TRACE = false;

// True if the message queue can be quit.
@UnsupportedAppUsage
private final boolean mQuitAllowed;

@UnsupportedAppUsage
@SuppressWarnings("unused")
private long mPtr; // used by native code

@UnsupportedAppUsage
Message mMessages;
private Message mLast;
@UnsupportedAppUsage
private final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<IdleHandler>();
private SparseArray<FileDescriptorRecord> mFileDescriptorRecords;
private IdleHandler[] mPendingIdleHandlers;
private boolean mQuitting;

// Indicates whether next() is blocked waiting in pollOnce() with a non-zero timeout.
private boolean mBlocked;

// Tracks the number of async message. We use this in enqueueMessage() to avoid searching the
// queue for async messages when inserting a message at the tail.
private int mAsyncMessageCount;

// The next barrier token.
// Barriers are indicated by messages with a null target whose arg1 field carries the token.
@UnsupportedAppUsage
private int mNextBarrierToken;

@RavenwoodRedirect
private native static long nativeInit();
@RavenwoodRedirect
private native static void nativeDestroy(long ptr);
@UnsupportedAppUsage
@RavenwoodRedirect
private native void nativePollOnce(long ptr, int timeoutMillis); /*non-static for callbacks*/
@RavenwoodRedirect
private native static void nativeWake(long ptr);
@RavenwoodRedirect
private native static boolean nativeIsPolling(long ptr);
@RavenwoodRedirect
private native static void nativeSetFileDescriptorEvents(long ptr, int fd, int events);

MessageQueue(boolean quitAllowed) {
mQuitAllowed = quitAllowed;
mPtr = nativeInit();
}

@android.ravenwood.annotation.RavenwoodReplace
private static void throwIfNotTest() {
final ActivityThread activityThread = ActivityThread.currentActivityThread();
if (activityThread == null) {
// Only tests can reach here.
return;
}
final Instrumentation instrumentation = activityThread.getInstrumentation();
if (instrumentation == null) {
// Only tests can reach here.
return;
}
if (instrumentation.isInstrumenting()) {
return;
}
throw new IllegalStateException("Test-only API called not from a test!");
}

private static void throwIfNotTest$ravenwood() {
return;
}

@Override
protected void finalize() throws Throwable {
try {
dispose();
} finally {
super.finalize();
}
}

// Disposes of the underlying message queue.
// Must only be called on the looper thread or the finalizer.
private void dispose() {
if (mPtr != 0) {
nativeDestroy(mPtr);
mPtr = 0;
}
}

/**
* Returns true if the looper has no pending messages which are due to be processed.
*
* <p>This method is safe to call from any thread.
*
* @return True if the looper is idle.
*/
public boolean isIdle() {
synchronized (this) {
final long now = SystemClock.uptimeMillis();
return mMessages == null || now < mMessages.when;
}
}

/**
* Add a new {@link IdleHandler} to this message queue. This may be
* removed automatically for you by returning false from
* {@link IdleHandler#queueIdle IdleHandler.queueIdle()} when it is
* invoked, or explicitly removing it with {@link #removeIdleHandler}.
*
* <p>This method is safe to call from any thread.
*
* @param handler The IdleHandler to be added.
*/
public void addIdleHandler(@NonNull IdleHandler handler) {
if (handler == null) {
throw new NullPointerException("Can't add a null IdleHandler");
}
synchronized (this) {
mIdleHandlers.add(handler);
}
}

/**
* Remove an {@link IdleHandler} from the queue that was previously added
* with {@link #addIdleHandler}. If the given object is not currently
* in the idle list, nothing is done.
*
* <p>This method is safe to call from any thread.
*
* @param handler The IdleHandler to be removed.
*/
public void removeIdleHandler(@NonNull IdleHandler handler) {
synchronized (this) {
mIdleHandlers.remove(handler);
}
}

/**
* Returns whether this looper's thread is currently polling for more work to do.
* This is a good signal that the loop is still alive rather than being stuck
* handling a callback. Note that this method is intrinsically racy, since the
* state of the loop can change before you get the result back.
*
* <p>This method is safe to call from any thread.
*
* @return True if the looper is currently polling for events.
* @hide
*/
public boolean isPolling() {
synchronized (this) {
return isPollingLocked();
}
}

private boolean isPollingLocked() {
// If the loop is quitting then it must not be idling.
// We can assume mPtr != 0 when mQuitting is false.
return !mQuitting && nativeIsPolling(mPtr);
}

/**
* Adds a file descriptor listener to receive notification when file descriptor
* related events occur.
* <p>
* If the file descriptor has already been registered, the specified events
* and listener will replace any that were previously associated with it.
* It is not possible to set more than one listener per file descriptor.
* </p><p>
* It is important to always unregister the listener when the file descriptor
* is no longer of use.
* </p>
*
* @param fd The file descriptor for which a listener will be registered.
* @param events The set of events to receive: a combination of the
* {@link OnFileDescriptorEventListener#EVENT_INPUT},
* {@link OnFileDescriptorEventListener#EVENT_OUTPUT}, and
* {@link OnFileDescriptorEventListener#EVENT_ERROR} event masks. If the requested
* set of events is zero, then the listener is unregistered.
* @param listener The listener to invoke when file descriptor events occur.
*
* @see OnFileDescriptorEventListener
* @see #removeOnFileDescriptorEventListener
*/
@android.ravenwood.annotation.RavenwoodThrow(blockedBy = android.os.ParcelFileDescriptor.class)
public void addOnFileDescriptorEventListener(@NonNull FileDescriptor fd,
@OnFileDescriptorEventListener.Events int events,
@NonNull OnFileDescriptorEventListener listener) {
if (fd == null) {
throw new IllegalArgumentException("fd must not be null");
}
if (listener == null) {
throw new IllegalArgumentException("listener must not be null");
}

synchronized (this) {
updateOnFileDescriptorEventListenerLocked(fd, events, listener);
}
}

/**
* Removes a file descriptor listener.
* <p>
* This method does nothing if no listener has been registered for the
* specified file descriptor.
* </p>
*
* @param fd The file descriptor whose listener will be unregistered.
*
* @see OnFileDescriptorEventListener
* @see #addOnFileDescriptorEventListener
*/
@android.ravenwood.annotation.RavenwoodThrow(blockedBy = android.os.ParcelFileDescriptor.class)
public void removeOnFileDescriptorEventListener(@NonNull FileDescriptor fd) {
if (fd == null) {
throw new IllegalArgumentException("fd must not be null");
}

synchronized (this) {
updateOnFileDescriptorEventListenerLocked(fd, 0, null);
}
}

@android.ravenwood.annotation.RavenwoodThrow(blockedBy = android.os.ParcelFileDescriptor.class)
private void updateOnFileDescriptorEventListenerLocked(FileDescriptor fd, int events,
OnFileDescriptorEventListener listener) {
final int fdNum = fd.getInt$();

int index = -1;
FileDescriptorRecord record = null;
if (mFileDescriptorRecords != null) {
index = mFileDescriptorRecords.indexOfKey(fdNum);
if (index >= 0) {
record = mFileDescriptorRecords.valueAt(index);
if (record != null && record.mEvents == events) {
return;
}
}
}

if (events != 0) {
events |= OnFileDescriptorEventListener.EVENT_ERROR;
if (record == null) {
if (mFileDescriptorRecords == null) {
mFileDescriptorRecords = new SparseArray<FileDescriptorRecord>();
}
record = new FileDescriptorRecord(fd, events, listener);
mFileDescriptorRecords.put(fdNum, record);
} else {
record.mListener = listener;
record.mEvents = events;
record.mSeq += 1;
}
nativeSetFileDescriptorEvents(mPtr, fdNum, events);
} else if (record != null) {
record.mEvents = 0;
mFileDescriptorRecords.removeAt(index);
nativeSetFileDescriptorEvents(mPtr, fdNum, 0);
}
}

// Called from native code.
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
private int dispatchEvents(int fd, int events) {
// Get the file descriptor record and any state that might change.
final FileDescriptorRecord record;
final int oldWatchedEvents;
final OnFileDescriptorEventListener listener;
final int seq;
synchronized (this) {
record = mFileDescriptorRecords.get(fd);
if (record == null) {
return 0; // spurious, no listener registered
}

oldWatchedEvents = record.mEvents;
events &= oldWatchedEvents; // filter events based on current watched set
if (events == 0) {
return oldWatchedEvents; // spurious, watched events changed
}

listener = record.mListener;
seq = record.mSeq;
}

// Invoke the listener outside of the lock.
int newWatchedEvents = listener.onFileDescriptorEvents(
record.mDescriptor, events);
if (newWatchedEvents != 0) {
newWatchedEvents |= OnFileDescriptorEventListener.EVENT_ERROR;
}

// Update the file descriptor record if the listener changed the set of
// events to watch and the listener itself hasn't been updated since.
if (newWatchedEvents != oldWatchedEvents) {
synchronized (this) {
int index = mFileDescriptorRecords.indexOfKey(fd);
if (index >= 0 && mFileDescriptorRecords.valueAt(index) == record
&& record.mSeq == seq) {
record.mEvents = newWatchedEvents;
if (newWatchedEvents == 0) {
mFileDescriptorRecords.removeAt(index);
}
}
}
}

// Return the new set of events to watch for native code to take care of.
return newWatchedEvents;
}

private static final AtomicLong mMessagesDelivered = new AtomicLong();

@UnsupportedAppUsage
Message next() {
// Return here if the message loop has already quit and been disposed.
// This can happen if the application tries to restart a looper after quit
// which is not supported.
final long ptr = mPtr;
if (ptr == 0) {
return null;
}

int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}

nativePollOnce(ptr, nextPollTimeoutMillis);

synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
if (msg != null && msg.target == null) {
// Stalled by a barrier. Find the next asynchronous message in the queue.
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
if (now < msg.when) {
// Next message is not ready. Set a timeout to wake up when it is ready.
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// Got a message.
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next;
if (prevMsg.next == null) {
mLast = prevMsg;
}
} else {
mMessages = msg.next;
if (msg.next == null) {
mLast = null;
}
}
msg.next = null;
if (DEBUG) Log.v(TAG, "Returning message: " + msg);
msg.markInUse();
if (msg.isAsynchronous()) {
mAsyncMessageCount--;
}
if (TRACE) {
Trace.setCounter("MQ.Delivered", mMessagesDelivered.incrementAndGet());
}
return msg;
}
} else {
// No more messages.
nextPollTimeoutMillis = -1;
}

// Process the quit message now that all pending messages have been handled.
if (mQuitting) {
dispose();
return null;
}

// If first time idle, then get the number of idlers to run.
// Idle handles only run if the queue is empty or if the first message
// in the queue (possibly a barrier) is due to be handled in the future.
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount <= 0) {
// No idle handlers to run. Loop and wait some more.
mBlocked = true;
continue;
}

if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
}

// Run the idle handlers.
// We only ever reach this code block during the first iteration.
for (int i = 0; i < pendingIdleHandlerCount; i++) {
final IdleHandler idler = mPendingIdleHandlers[i];
mPendingIdleHandlers[i] = null; // release the reference to the handler

boolean keep = false;
try {
keep = idler.queueIdle();
} catch (Throwable t) {
Log.wtf(TAG, "IdleHandler threw exception", t);
}

if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}

// Reset the idle handler count to 0 so we do not run them again.
pendingIdleHandlerCount = 0;

// While calling an idle handler, a new message could have been delivered
// so go back and look again for a pending message without waiting.
nextPollTimeoutMillis = 0;
}
}

void quit(boolean safe) {
if (!mQuitAllowed) {
throw new IllegalStateException("Main thread not allowed to quit.");
}

synchronized (this) {
if (mQuitting) {
return;
}
mQuitting = true;

if (safe) {
removeAllFutureMessagesLocked();
} else {
removeAllMessagesLocked();
}

// We can assume mPtr != 0 because mQuitting was previously false.
nativeWake(mPtr);
}
}

/**
* Posts a synchronization barrier to the Looper's message queue.
*
* Message processing occurs as usual until the message queue encounters the
* synchronization barrier that has been posted. When the barrier is encountered,
* later synchronous messages in the queue are stalled (prevented from being executed)
* until the barrier is released by calling {@link #removeSyncBarrier} and specifying
* the token that identifies the synchronization barrier.
*
* This method is used to immediately postpone execution of all subsequently posted
* synchronous messages until a condition is met that releases the barrier.
* Asynchronous messages (see {@link Message#isAsynchronous} are exempt from the barrier
* and continue to be processed as usual.
*
* This call must be always matched by a call to {@link #removeSyncBarrier} with
* the same token to ensure that the message queue resumes normal operation.
* Otherwise the application will probably hang!
*
* @return A token that uniquely identifies the barrier. This token must be
* passed to {@link #removeSyncBarrier} to release the barrier.
*
* @hide
*/
@UnsupportedAppUsage
@TestApi
public int postSyncBarrier() {
return postSyncBarrier(SystemClock.uptimeMillis());
}

private int postSyncBarrier(long when) {
// Enqueue a new sync barrier token.
// We don't need to wake the queue because the purpose of a barrier is to stall it.
synchronized (this) {
final int token = mNextBarrierToken++;
final Message msg = Message.obtain();
msg.markInUse();
msg.when = when;
msg.arg1 = token;

if (Flags.messageQueueTailTracking() && mLast != null && mLast.when <= when) {
/* Message goes to tail of list */
mLast.next = msg;
mLast = msg;
msg.next = null;
return token;
}

Message prev = null;
Message p = mMessages;
if (when != 0) {
while (p != null && p.when <= when) {
prev = p;
p = p.next;
}
}

if (p == null) {
/* We reached the tail of the list, or list is empty. */
mLast = msg;
}

if (prev != null) { // invariant: p == prev.next
msg.next = p;
prev.next = msg;
} else {
msg.next = p;
mMessages = msg;
}
return token;
}
}

/**
* Removes a synchronization barrier.
*
* @param token The synchronization barrier token that was returned by
* {@link #postSyncBarrier}.
*
* @throws IllegalStateException if the barrier was not found.
*
* @hide
*/
@UnsupportedAppUsage
@TestApi
public void removeSyncBarrier(int token) {
// Remove a sync barrier token from the queue.
// If the queue is no longer stalled by a barrier then wake it.
synchronized (this) {
Message prev = null;
Message p = mMessages;
while (p != null && (p.target != null || p.arg1 != token)) {
prev = p;
p = p.next;
}
if (p == null) {
throw new IllegalStateException("The specified message queue synchronization "
+ " barrier token has not been posted or has already been removed.");
}
final boolean needWake;
if (prev != null) {
prev.next = p.next;
if (prev.next == null) {
mLast = prev;
}
needWake = false;
} else {
mMessages = p.next;
if (mMessages == null) {
mLast = null;
}
needWake = mMessages == null || mMessages.target != null;
}
p.recycleUnchecked();

// If the loop is quitting then it is already awake.
// We can assume mPtr != 0 when mQuitting is false.
if (needWake && !mQuitting) {
nativeWake(mPtr);
}
}
}

boolean enqueueMessage(Message msg, long when) {
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}

synchronized (this) {
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}

if (mQuitting) {
IllegalStateException e = new IllegalStateException(
msg.target + " sending message to a Handler on a dead thread");
Log.w(TAG, e.getMessage(), e);
msg.recycle();
return false;
}

msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
msg.next = p;
mMessages = msg;
needWake = mBlocked;
if (p == null) {
mLast = mMessages;
}
} else {
// Message is to be inserted at tail or middle of queue. Usually we don't have to
// wake up the event queue unless there is a barrier at the head of the queue and
// the message is the earliest asynchronous message in the queue.
needWake = mBlocked && p.target == null && msg.isAsynchronous();

// For readability, we split this portion of the function into two blocks based on
// whether tail tracking is enabled. This has a minor implication for the case
// where tail tracking is disabled. See the comment below.
if (Flags.messageQueueTailTracking()) {
if (when >= mLast.when) {
needWake = needWake && mAsyncMessageCount == 0;
msg.next = null;
mLast.next = msg;
mLast = msg;
} else {
// Inserted within the middle of the queue.
Message prev;
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
if (p == null) {
/* Inserting at tail of queue */
mLast = msg;
}
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
} else {
Message prev;
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
msg.next = p; // invariant: p == prev.next
prev.next = msg;

/*
* If this block is executing then we have a build without tail tracking -
* specifically: Flags.messageQueueTailTracking() == false. This is determined
* at build time so the flag won't change on us during runtime.
*
* Since we don't want to pepper the code with extra checks, we only check
* for tail tracking when we might use mLast. Otherwise, we continue to update
* mLast as the tail of the list.
*
* In this case however we are not maintaining mLast correctly. Since we never
* use it, this is fine. However, we run the risk of leaking a reference.
* So set mLast to null in this case to avoid any Message leaks. The other
* sites will never use the value so we are safe against null pointer derefs.
*/
mLast = null;
}
}

if (msg.isAsynchronous()) {
mAsyncMessageCount++;
}

// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}

private Message legacyPeekOrPoll(boolean peek) {
synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
if (msg != null && msg.target == null) {
// Stalled by a barrier. Find the next asynchronous message in the queue.
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
if (peek) {
return msg;
}
if (now >= msg.when) {
// Got a message.
mBlocked = false;
}
if (prevMsg != null) {
prevMsg.next = msg.next;
if (prevMsg.next == null) {
mLast = prevMsg;
}
} else {
mMessages = msg.next;
if (msg.next == null) {
mLast = null;
}
}
msg.next = null;
msg.markInUse();
if (msg.isAsynchronous()) {
mAsyncMessageCount--;
}
if (TRACE) {
Trace.setCounter("MQ.Delivered", mMessagesDelivered.incrementAndGet());
}
return msg;
}
}
return null;
}

/**
* Get the timestamp of the next message in our priority queue.
* Returns null if there are no messages in the queue.
*
* Caller must ensure that this doesn't race 'next' from the Looper thread.
*/
@SuppressLint("VisiblySynchronized") // Legacy MessageQueue synchronizes on this
Long peekWhenForTest() {
throwIfNotTest();
Message ret = legacyPeekOrPoll(true);
return ret != null ? ret.when : null;
}

/**
* Return the next message in our priority queue.
* Returns null if there are no messages in the queue.
*
* Caller must ensure that this doesn't race 'next' from the Looper thread.
*/
@SuppressLint("VisiblySynchronized") // Legacy MessageQueue synchronizes on this
@Nullable
Message pollForTest() {
throwIfNotTest();
return legacyPeekOrPoll(false);
}

/**
* @return true if we are blocked on a sync barrier
*
* Calls to this method must not be allowed to race with `next`.
* Specifically, the Looper thread must be paused before calling this method,
* and may not be resumed until after returning from this method.
*/
boolean isBlockedOnSyncBarrier() {
throwIfNotTest();
synchronized (this) {
Message msg = mMessages;
return msg != null && msg.target == null;
}
}

boolean hasMessages(Handler h, int what, Object object) {
if (h == null) {
return false;
}

synchronized (this) {
Message p = mMessages;
while (p != null) {
if (p.target == h && p.what == what && (object == null || p.obj == object)) {
return true;
}
p = p.next;
}
return false;
}
}

boolean hasEqualMessages(Handler h, int what, Object object) {
if (h == null) {
return false;
}

synchronized (this) {
Message p = mMessages;
while (p != null) {
if (p.target == h && p.what == what && (object == null || object.equals(p.obj))) {
return true;
}
p = p.next;
}
return false;
}
}

@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
boolean hasMessages(Handler h, Runnable r, Object object) {
if (h == null) {
return false;
}

synchronized (this) {
Message p = mMessages;
while (p != null) {
if (p.target == h && p.callback == r && (object == null || p.obj == object)) {
return true;
}
p = p.next;
}
return false;
}
}

boolean hasMessages(Handler h) {
if (h == null) {
return false;
}

synchronized (this) {
Message p = mMessages;
while (p != null) {
if (p.target == h) {
return true;
}
p = p.next;
}
return false;
}
}

void removeMessages(Handler h, int what, Object object) {
if (h == null) {
return;
}

synchronized (this) {
Message p = mMessages;

// Remove all messages at front.
while (p != null && p.target == h && p.what == what
&& (object == null || p.obj == object)) {
Message n = p.next;
mMessages = n;
if (p.isAsynchronous()) {
mAsyncMessageCount--;
}
p.recycleUnchecked();
p = n;
}

if (p == null) {
mLast = mMessages;
}

// Remove all messages after front.
while (p != null) {
Message n = p.next;
if (n != null) {
if (n.target == h && n.what == what
&& (object == null || n.obj == object)) {
Message nn = n.next;
if (n.isAsynchronous()) {
mAsyncMessageCount--;
}
n.recycleUnchecked();
p.next = nn;
if (p.next == null) {
mLast = p;
}
continue;
}
}
p = n;
}
}
}

void removeEqualMessages(Handler h, int what, Object object) {
if (h == null) {
return;
}

synchronized (this) {
Message p = mMessages;

// Remove all messages at front.
while (p != null && p.target == h && p.what == what
&& (object == null || object.equals(p.obj))) {
Message n = p.next;
mMessages = n;
if (p.isAsynchronous()) {
mAsyncMessageCount--;
}
p.recycleUnchecked();
p = n;
}

if (p == null) {
mLast = mMessages;
}

// Remove all messages after front.
while (p != null) {
Message n = p.next;
if (n != null) {
if (n.target == h && n.what == what
&& (object == null || object.equals(n.obj))) {
Message nn = n.next;
if (n.isAsynchronous()) {
mAsyncMessageCount--;
}
n.recycleUnchecked();
p.next = nn;
if (p.next == null) {
mLast = p;
}
continue;
}
}
p = n;
}
}
}

void removeMessages(Handler h, Runnable r, Object object) {
if (h == null || r == null) {
return;
}

synchronized (this) {
Message p = mMessages;

// Remove all messages at front.
while (p != null && p.target == h && p.callback == r
&& (object == null || p.obj == object)) {
Message n = p.next;
mMessages = n;
if (p.isAsynchronous()) {
mAsyncMessageCount--;
}
p.recycleUnchecked();
p = n;
}

if (p == null) {
mLast = mMessages;
}

// Remove all messages after front.
while (p != null) {
Message n = p.next;
if (n != null) {
if (n.target == h && n.callback == r
&& (object == null || n.obj == object)) {
Message nn = n.next;
if (n.isAsynchronous()) {
mAsyncMessageCount--;
}
n.recycleUnchecked();
p.next = nn;
if (p.next == null) {
mLast = p;
}
continue;
}
}
p = n;
}
}
}

void removeEqualMessages(Handler h, Runnable r, Object object) {
if (h == null || r == null) {
return;
}

synchronized (this) {
Message p = mMessages;

// Remove all messages at front.
while (p != null && p.target == h && p.callback == r
&& (object == null || object.equals(p.obj))) {
Message n = p.next;
mMessages = n;
if (p.isAsynchronous()) {
mAsyncMessageCount--;
}
p.recycleUnchecked();
p = n;
}

if (p == null) {
mLast = mMessages;
}

// Remove all messages after front.
while (p != null) {
Message n = p.next;
if (n != null) {
if (n.target == h && n.callback == r
&& (object == null || object.equals(n.obj))) {
Message nn = n.next;
if (n.isAsynchronous()) {
mAsyncMessageCount--;
}
n.recycleUnchecked();
p.next = nn;
if (p.next == null) {
mLast = p;
}
continue;
}
}
p = n;
}
}
}


void removeCallbacksAndMessages(Handler h, Object object) {
if (h == null) {
return;
}

synchronized (this) {
Message p = mMessages;

// Remove all messages at front.
while (p != null && p.target == h
&& (object == null || p.obj == object)) {
Message n = p.next;
mMessages = n;
if (p.isAsynchronous()) {
mAsyncMessageCount--;
}
p.recycleUnchecked();
p = n;
}

if (p == null) {
mLast = mMessages;
}

// Remove all messages after front.
while (p != null) {
Message n = p.next;
if (n != null) {
if (n.target == h && (object == null || n.obj == object)) {
Message nn = n.next;
if (n.isAsynchronous()) {
mAsyncMessageCount--;
}
n.recycleUnchecked();
p.next = nn;
if (p.next == null) {
mLast = p;
}
continue;
}
}
p = n;
}
}
}

void removeCallbacksAndEqualMessages(Handler h, Object object) {
if (h == null) {
return;
}

synchronized (this) {
Message p = mMessages;

// Remove all messages at front.
while (p != null && p.target == h
&& (object == null || object.equals(p.obj))) {
Message n = p.next;
mMessages = n;
if (p.isAsynchronous()) {
mAsyncMessageCount--;
}
p.recycleUnchecked();
p = n;
}

if (p == null) {
mLast = mMessages;
}

// Remove all messages after front.
while (p != null) {
Message n = p.next;
if (n != null) {
if (n.target == h && (object == null || object.equals(n.obj))) {
Message nn = n.next;
if (n.isAsynchronous()) {
mAsyncMessageCount--;
}
n.recycleUnchecked();
p.next = nn;
if (p.next == null) {
mLast = p;
}
continue;
}
}
p = n;
}
}
}

private void removeAllMessagesLocked() {
Message p = mMessages;
while (p != null) {
Message n = p.next;
p.recycleUnchecked();
p = n;
}
mMessages = null;
mLast = null;
mAsyncMessageCount = 0;
}

private void removeAllFutureMessagesLocked() {
final long now = SystemClock.uptimeMillis();
Message p = mMessages;
if (p != null) {
if (p.when > now) {
removeAllMessagesLocked();
} else {
Message n;
for (;;) {
n = p.next;
if (n == null) {
return;
}
if (n.when > now) {
break;
}
p = n;
}
p.next = null;
mLast = p;

do {
p = n;
n = p.next;
if (p.isAsynchronous()) {
mAsyncMessageCount--;
}
p.recycleUnchecked();
} while (n != null);
}
}
}

@NeverCompile
void dump(Printer pw, String prefix, Handler h) {
synchronized (this) {
pw.println(prefix + "(MessageQueue is using Legacy implementation)");
long now = SystemClock.uptimeMillis();
int n = 0;
for (Message msg = mMessages; msg != null; msg = msg.next) {
if (h == null || h == msg.target) {
pw.println(prefix + "Message " + n + ": " + msg.toString(now));
}
n++;
}
pw.println(prefix + "(Total messages: " + n + ", polling=" + isPollingLocked()
+ ", quitting=" + mQuitting + ")");
}
}

@NeverCompile
void dumpDebug(ProtoOutputStream proto, long fieldId) {
final long messageQueueToken = proto.start(fieldId);
synchronized (this) {
for (Message msg = mMessages; msg != null; msg = msg.next) {
msg.dumpDebug(proto, MessageQueueProto.MESSAGES);
}
proto.write(MessageQueueProto.IS_POLLING_LOCKED, isPollingLocked());
proto.write(MessageQueueProto.IS_QUITTING, mQuitting);
}
proto.end(messageQueueToken);
}

/**
* Callback interface for discovering when a thread is going to block
* waiting for more messages.
*/
public static interface IdleHandler {
/**
* Called when the message queue has run out of messages and will now
* wait for more. Return true to keep your idle handler active, false
* to have it removed. This may be called if there are still messages
* pending in the queue, but they are all scheduled to be dispatched
* after the current time.
*/
boolean queueIdle();
}

/**
* A listener which is invoked when file descriptor related events occur.
*/
public interface OnFileDescriptorEventListener {
/**
* File descriptor event: Indicates that the file descriptor is ready for input
* operations, such as reading.
* <p>
* The listener should read all available data from the file descriptor
* then return <code>true</code> to keep the listener active or <code>false</code>
* to remove the listener.
* </p><p>
* In the case of a socket, this event may be generated to indicate
* that there is at least one incoming connection that the listener
* should accept.
* </p><p>
* This event will only be generated if the {@link #EVENT_INPUT} event mask was
* specified when the listener was added.
* </p>
*/
public static final int EVENT_INPUT = 1 << 0;

/**
* File descriptor event: Indicates that the file descriptor is ready for output
* operations, such as writing.
* <p>
* The listener should write as much data as it needs. If it could not
* write everything at once, then it should return <code>true</code> to
* keep the listener active. Otherwise, it should return <code>false</code>
* to remove the listener then re-register it later when it needs to write
* something else.
* </p><p>
* This event will only be generated if the {@link #EVENT_OUTPUT} event mask was
* specified when the listener was added.
* </p>
*/
public static final int EVENT_OUTPUT = 1 << 1;

/**
* File descriptor event: Indicates that the file descriptor encountered a
* fatal error.
* <p>
* File descriptor errors can occur for various reasons. One common error
* is when the remote peer of a socket or pipe closes its end of the connection.
* </p><p>
* This event may be generated at any time regardless of whether the
* {@link #EVENT_ERROR} event mask was specified when the listener was added.
* </p>
*/
public static final int EVENT_ERROR = 1 << 2;

/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(flag = true, prefix = { "EVENT_" }, value = {
EVENT_INPUT,
EVENT_OUTPUT,
EVENT_ERROR
})
public @interface Events {}

/**
* Called when a file descriptor receives events.
*
* @param fd The file descriptor.
* @param events The set of events that occurred: a combination of the
* {@link #EVENT_INPUT}, {@link #EVENT_OUTPUT}, and {@link #EVENT_ERROR} event masks.
* @return The new set of events to watch, or 0 to unregister the listener.
*
* @see #EVENT_INPUT
* @see #EVENT_OUTPUT
* @see #EVENT_ERROR
*/
@Events int onFileDescriptorEvents(@NonNull FileDescriptor fd, @Events int events);
}

private static final class FileDescriptorRecord {
public final FileDescriptor mDescriptor;
public int mEvents;
public OnFileDescriptorEventListener mListener;
public int mSeq;

public FileDescriptorRecord(FileDescriptor descriptor,
int events, OnFileDescriptorEventListener listener) {
mDescriptor = descriptor;
mEvents = events;
mListener = listener;
}
}
}

Android 17 MessageQueue 线程锁

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
/*
* Copyright (C) 2025 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package android.os;

import static android.os.Message.*;

import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.annotation.TestApi;
import android.app.ActivityThread;
import android.compat.annotation.UnsupportedAppUsage;
import android.ravenwood.annotation.RavenwoodKeepWholeClass;
import android.ravenwood.annotation.RavenwoodRedirect;
import android.ravenwood.annotation.RavenwoodRedirectionClass;
import android.ravenwood.annotation.RavenwoodReplace;
import android.ravenwood.annotation.RavenwoodThrow;
import android.util.Log;
import android.util.Printer;
import android.util.SparseArray;
import android.util.proto.ProtoOutputStream;

import dalvik.annotation.optimization.NeverCompile;

import java.io.FileDescriptor;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.NoSuchElementException;
import java.util.concurrent.ConcurrentSkipListSet;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.LockSupport;
import java.util.concurrent.locks.ReentrantLock;

/**
* MessageQueue
* 这是一个低层级类,用于持有将由 Looper 分发的消息列表。
* 消息通常不直接添加到 MessageQueue 中,而是通过与 Looper 关联的 Handler 对象进行添加。
*
* 您可以通过 Looper.myQueue() 获取当前线程的 MessageQueue 实例。
*/
@RavenwoodKeepWholeClass
@RavenwoodRedirectionClass("MessageQueue_ravenwood")
public final class MessageQueue {
private static final String TAG = "DeliQueue";
private static final boolean DEBUG = false;

// 若消息队列可以退出,则为 true。
@UnsupportedAppUsage
private final boolean mQuitAllowed;

@UnsupportedAppUsage
@SuppressWarnings("unused")
private long mPtr; // 被 Native 代码调用

@RavenwoodRedirect
private native static long nativeInit();
@RavenwoodRedirect
private native static void nativeDestroy(long ptr);
@UnsupportedAppUsage
@RavenwoodRedirect
private native void nativePollOnce(long ptr, int timeoutMillis); /*non-static for callbacks*/

@RavenwoodRedirect
private native static void nativeWake(long ptr);
@RavenwoodRedirect
private native static boolean nativeIsPolling(long ptr);
@RavenwoodRedirect
private native static void nativeSetFileDescriptorEvents(long ptr, int fd, int events);
@RavenwoodRedirect
private native static void nativeSetSkipEpollWaitForZeroTimeout(long ptr);

@UnsupportedAppUsage
private final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<IdleHandler>();
private SparseArray<FileDescriptorRecord> mFileDescriptorRecords;
private IdleHandler[] mPendingIdleHandlers;

private final Object mIdleHandlersLock = new Object();
private final Object mFileDescriptorRecordsLock = new Object();

private final AtomicLong mMessageCount = new AtomicLong();
private final Thread mLooperThread;
private final String mThreadName;
private final long mTid;

MessageStack mStack = new MessageStack();

/*
* 这有助于我们确保具有相同时间戳的消息按 FIFO(先进先出) 顺序插入。
* 每次插入时该值递增,从 0 开始。当分发时间戳相同时,MessageNode.compareTo() 将通过比较该序列号(Sequence)来决定先后。
*/
private static final VarHandle sNextInsertSeq;
private volatile long mNextInsertSeqValue = 0;
/*
* FIFO 排序规则的例外是 sendMessageAtFrontOfQueue()。
* 这类消息必须遵循 LIFO(后进先出) 顺序。
* 每次向队列头部插入时,该值递减。
*/
private static final VarHandle sNextFrontInsertSeq;
private volatile long mNextFrontInsertSeqValue = -1;

private static final VarHandle sWaitState;
private volatile long mWaitState;

/*
* 对我们访问 mPtr 的过程进行引用计数。
* next() 方法在 quit() 被调用之前不希望销毁 mPtr。
* isPolling() 同样需要确保对 mPtr 的安全访问。
* 因此,我们需要维持一个访问 mPtr 的引用计数。如果设置了“正在退出(quitting)”标志,我们将禁止产生新的引用。
* 只有当所有引用都释放后,next() 才会继续执行销毁该指针的操作。
*/
private static final VarHandle sMptrRefCount;
private volatile long mMptrRefCountValue = 0;

private static final VarHandle sSyncBarrier;
private volatile Message mSyncBarrier = null;

static {
try {
// 出于性能原因,我们需要使用 VarHandle,而不是 java.util.concurrent.atomic. 相关的类。
// 参见:b/421437036*
MethodHandles.Lookup l = MethodHandles.lookup();
sNextInsertSeq = l.findVarHandle(MessageQueue.class, "mNextInsertSeqValue",
long.class);
sNextFrontInsertSeq = l.findVarHandle(MessageQueue.class, "mNextFrontInsertSeqValue",
long.class);
sWaitState = l.findVarHandle(MessageQueue.class, "mWaitState",
long.class);
sMptrRefCount = l.findVarHandle(MessageQueue.class, "mMptrRefCountValue",
long.class);
sSyncBarrier = l.findVarHandle(MessageQueue.class, "mSyncBarrier",
Message.class);
} catch (ReflectiveOperationException e) {
throw new ExceptionInInitializerError(e);
}
}
// 使用最高有效位(MSB)来表示 mPtr 的拆卸(teardown)状态。低 63 位用于持有引用计数。
private static final long MPTR_TEARDOWN_MASK = 1L << 63;

/**
* 增加 mPtr 的引用计数。
*
* 如果此方法返回 true,则调用者可以持续使用 mPtr,直到调用 {@link #decrementMptrRefs()} 为止。
* 如果此方法返回 false,则调用者绝不可使用 mPtr,而应假定 MessageQueue 正在退出或已经退出,并采取相应的处理措施。
*/
private boolean incrementMptrRefs() {
while (true) {
final long oldVal = mMptrRefCountValue;
if ((oldVal & MPTR_TEARDOWN_MASK) != 0) {
// 如果队列正在退出,则不允许增加引用计数。
return false;
}
if (sMptrRefCount.compareAndSet(this, oldVal, oldVal + 1)) {
// 成功增加引用计数,且此时队列并未退出。
return true;
}
}
}

/**
* 减少 mPtr 的引用计数。
*
* 在调用 {@link #incrementMptrRefs()} 之后调用此方法,以释放对 mPtr 的引用。
*/
private void decrementMptrRefs() {
long oldVal = (long) sMptrRefCount.getAndAdd(this, -1);
// If quitting and we were the last ref, wake up looper thread
if (oldVal - 1 == MPTR_TEARDOWN_MASK) {
LockSupport.unpark(mLooperThread);
}
}

/**
* 唤醒 Looper 线程。
*
* 只有 Looper 线程可以直接调用 {@link #nativeWake(long)}。
* 否则,必须调用此方法,以确保对 mPtr 的安全访问。
*/
private void concurrentWake() {
if (incrementMptrRefs()) {
try {
nativeWake(mPtr);
} finally {
decrementMptrRefs();
}
}
}

// 必须仅从 Looper 线程调用
private void setMptrTeardownAndWaitForRefsToDrop() {
if (DEBUG && Thread.currentThread() != mLooperThread) {
throw new IllegalStateException(
"setMptrTeardownAndWaitForRefsToDrop must only be called from looper thread");
}
while (true) {
final long oldVal = mMptrRefCountValue;
if (sMptrRefCount.compareAndSet(this, oldVal, oldVal | MPTR_TEARDOWN_MASK)) {
// 成功设置了销毁状态。
break;
}
}

boolean wasInterrupted = false;
try {
while ((mMptrRefCountValue & ~MPTR_TEARDOWN_MASK) != 0) {
LockSupport.park();
wasInterrupted |= Thread.interrupted();
}
} finally {
if (wasInterrupted) {
mLooperThread.interrupt();
}
}
}

static boolean getUseConcurrent() {
return true;
}

private static boolean isBarrier(Message msg) {
return msg != null && msg.target == null;
}

MessageQueue(boolean quitAllowed) {
mQuitAllowed = quitAllowed;
mPtr = nativeInit();
mLooperThread = Thread.currentThread();
mThreadName = mLooperThread.getName();
mTid = Process.myTid();
long now = SystemClock.uptimeMillis();
mWaitState = WaitState.composeDeadline(now + INDEFINITE_TIMEOUT_MS, false);
}

// 处置底层的消息队列。
// 必须仅在 Looper 线程或终结器(Finalizer)中调用。
private void dispose() {
if (mPtr != 0) {
nativeDestroy(mPtr);
mPtr = 0;
}
}

@SuppressWarnings("Finalize")
@Override
protected void finalize() throws Throwable {
try {
dispose();
} finally {
super.finalize();
}
}

@NeverCompile
private static void logDeadThread(Message msg) {
IllegalStateException e = new IllegalStateException(
msg.target + " sending message to a Handler on a dead thread");
Log.w(TAG, e.getMessage(), e);
msg.recycleUnchecked();
}

private boolean enqueueMessageUnchecked(@NonNull Message msg, long when) {
long seq = when != 0 ? ((long) sNextInsertSeq.getAndAdd(this, 1L) + 1L)
: ((long) sNextFrontInsertSeq.getAndAdd(this, -1L) - 1L);
msg.when = when;
msg.insertSeq = seq;
msg.markInUse();
incAndTraceMessageCount(msg, when);

if (!mStack.pushMessage(msg)) {
logDeadThread(msg);
decAndTraceMessageCount();
return false;
}

if (DEBUG) {
Log.d(TAG, "Insert message"
+ " what: " + msg.what
+ " when: " + msg.when
+ " seq: " + msg.insertSeq
+ " barrier: " + isBarrier(msg)
+ " async: " + msg.isAsynchronous()
+ " now: " + SystemClock.uptimeMillis());
}

while (true) {
long waitState = mWaitState;
long newWaitState;
boolean needWake = false;
Message barrier = msg.isAsynchronous() ? null :
(Message) sSyncBarrier.getVolatile(this);
boolean reCheckBarrier = false;

if (WaitState.isCounter(waitState)) {
newWaitState = WaitState.incrementCounter(waitState);
} else {
final long TSmillis = WaitState.getTSMillis(waitState);
boolean weComeBeforeBarrier = barrier != null && msg.when <= barrier.when;
if (weComeBeforeBarrier || (msg.when < TSmillis
&& (!WaitState.hasSyncBarrier(waitState) || msg.isAsynchronous()))) {
newWaitState = WaitState.initCounter();
needWake = true;
} else {
newWaitState = WaitState.incrementDeadline(waitState);
reCheckBarrier = true;
}
}
if (sWaitState.compareAndSet(this, waitState, newWaitState)) {
if (reCheckBarrier && barrier != (Message) sSyncBarrier.getVolatile(this)) {
/*
* 如果屏障状态在我们操作期间发生了变化,
* 且我们(当时)选择了不唤醒 Looper 线程,
* 那么我们必须重新检查,
* 以确保在我们执行 CAS(原子操作)时,
* 所看到的屏障确实依然存在。
*/
continue;
}
if (needWake) {
concurrentWake();
}
return true;
}
}
}

boolean enqueueMessage(Message msg, long when) {
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}

return enqueueMessageUnchecked(msg, when);
}

/* 这些(变量/字段)仅由 Looper 线程读取或写入。 */
private int mNextPollTimeoutMillis;
private static int INDEFINITE_TIMEOUT_MS = 600_000_000;
private boolean mWorkerShouldQuit;
Message nextMessage(boolean peek, boolean returnEarliest) {
while (true) {
/*
* 一旦我们(的状态)被转换为计数器模式,只有 Looper 线程才能将等待状态(waitstate)重新改回时间戳模式。
*/
long oldWaitState = mWaitState;
final long zeroCounter = WaitState.initCounter();
while (!WaitState.isCounter(oldWaitState)) {
if (sWaitState.compareAndSet(this, oldWaitState, zeroCounter)) {
oldWaitState = zeroCounter;
break;
}
oldWaitState = mWaitState;
}

mStack.heapSweep();
mStack.drainFreelist();

boolean shouldRemoveMessages = false;
if (mStack.isQuitting()) {
if (!mWorkerShouldQuit) {
mWorkerShouldQuit = true;
long TS = mStack.getQuittingTimestamp();
if (TS == 0) {
removeAllMessages();
} else {
removeAllFutureMessages(TS);
}
}
}

Message msg = mStack.peek(false);
Message asyncMsg = mStack.peek(true);
final long now = SystemClock.uptimeMillis();

if (DEBUG) {
if (msg != null) {
Log.d(TAG, "Next found node"
+ " what: " + msg.what
+ " when: " + msg.when
+ " seq: " + msg.insertSeq
+ " barrier: " + isBarrier(msg)
+ " now: " + now);
}
if (asyncMsg != null) {
Log.d(TAG, "Next found async node"
+ " what: " + asyncMsg.what
+ " when: " + asyncMsg.when
+ " seq: " + asyncMsg.insertSeq
+ " barrier: " + isBarrier(asyncMsg)
+ " now: " + now);
}
}

/*
* 我们将要返回的节点;如果没有就绪的消息,则为 null。
*/
Message found = null;

/*
* 我们将根据此节点来确定下一次唤醒时间。
* Null 表示没有下一条就绪的消息。如果我们已经找到了一个(待处理的)节点,
* 那么可以将此变量保持为 null,因为 Looper 在分发完该消息后会再次调用我们。
*/
Message next = null;

Message syncBarrier = null;

/*
* 如果我们遇到了(同步)屏障,则应当返回异步节点(如果它存在且已就绪)。
*/
if (isBarrier(msg)) {
// 如果当前消息是屏障
if (asyncMsg != null && (returnEarliest || now >= asyncMsg.when)) {
// 如果存在异步消息,且(要求立即返回 或 异步消息已到期)
found = asyncMsg;
} else {
// 否则,记录此屏障,并将异步消息设为下一个唤醒参考点
syncBarrier = msg;
next = asyncMsg;
}
} else { /* 无屏障状态 */
// 从下一条同步消息和异步消息中选取最早的那一个(如果存在)
Message earliest = msg;
if (msg == null) {
earliest = asyncMsg;
} else if (asyncMsg != null) {
// 比较同步消息和异步消息的时间戳,取较早者
if (Message.compareMessages(msg, asyncMsg) > 0) {
earliest = asyncMsg;
}
}

if (earliest != null) {
if (returnEarliest || now >= earliest.when) {
// 如果最早的消息已就绪,则将其标记为待返回
found = earliest;
} else {
// 否则,将其设为下一次唤醒的参考时间点
next = earliest;
}
}
}

if (DEBUG) {
if (found != null) {
Log.d(TAG, "Will deliver node"
+ " what: " + found.what
+ " when: " + found.when
+ " seq: " + found.insertSeq
+ " barrier: " + isBarrier(found)
+ " async: " + found.isAsynchronous()
+ " now: " + now);
} else {
Log.d(TAG, "No node to deliver");
}
if (next != null) {
Log.d(TAG, "Next node"
+ " what: " + next.what
+ " when: " + next.when
+ " seq: " + next.insertSeq
+ " barrier: " + isBarrier(next)
+ " async: " + next.isAsynchronous()
+ " now: " + now);
} else {
Log.d(TAG, "No next node");
}
}

/*
* 如果我们已经找到了(待处理的)消息,由于之后还会被再次调用,因此无需设置状态。
* 否则,我们应当确定如何挂起(park)线程。
* mNextPollTimeoutMillis 具有某些特殊含义,无法直接转换为我们的 WaitState 所需的截止时间(deadline)。
* 因此,使用一个独立的变量来追踪等待状态的截止时间。
*/
long nextDeadline = 0; // 下一次截止时间
if (found == null) {
// 如果没有找到当前需要立即处理的消息
if (mWorkerShouldQuit) {
// 如果工作线程应该退出,将超时设为 0,这样我们不会阻塞 Looper,可以立即执行退出流程。
mNextPollTimeoutMillis = 0;
} else if (next == null) {
/* 没有可分发的消息,无限期休眠 */
mNextPollTimeoutMillis = INDEFINITE_TIMEOUT_MS; // 对应 native 层的 -1
nextDeadline = now + INDEFINITE_TIMEOUT_MS;
if (DEBUG) {
Log.d(TAG, "nextMessage 下一个等待状态为:无限期超时");
}
} else {
/* 消息尚未就绪,或者我们已经找到了一个待分发的消息,设置一个超时时间 */
long nextMessageWhen = next.when;
if (nextMessageWhen > now) {
// 如果下一条消息的时间还没到,计算需要等待的毫秒数
// 使用 Math.min 确保不会超过 Integer 的最大值
mNextPollTimeoutMillis = (int) Math.min(nextMessageWhen - now,
Integer.MAX_VALUE);
nextDeadline = now + mNextPollTimeoutMillis;
} else {
// 消息时间已到,无需等待
mNextPollTimeoutMillis = 0;
}

if (DEBUG) {
Log.d(TAG, "nextMessage 下一次等待"
+ " 超时毫秒数: " + mNextPollTimeoutMillis
+ " 当前时间: " + now);
}
}
}
sSyncBarrier.setVolatile(this, syncBarrier);
/*
* 尝试将等待状态(waitstate)从“计数器模式”切换回“截止时间模式”。
* 如果切换失败,意味着计数器(在此期间)被增加了,
* 我们需要重新循环以提取任何新加入的消息项。
*/
if (!sWaitState.compareAndSet(this, oldWaitState,
WaitState.composeDeadline(nextDeadline, syncBarrier != null))) {
continue;
}

if (found != null || nextDeadline != 0) {
if (found != null && !peek) {
// 如果找到了消息且不是“窥视”模式(即需要真正取出消息)
if (!found.markRemoved()) {
// 如果标记移除失败(可能消息已被其他线程处理),则重新循环
continue;
}
// 从消息栈/链表中移除该消息
mStack.remove(found);
}
// 返回找到的消息(如果没有找到则返回 null,但会带上计算好的超时时间)
return found;
}
return null;
}
}

Message next() {
final long ptr = mPtr; // 保存 Native 层的指针
if (ptr == 0) {
return null; // 如果指针已销毁,直接返回
}

mNextPollTimeoutMillis = 0; // 下次轮询的超时时间,0 表示立即检查
int pendingIdleHandlerCount = -1; // 待处理的空闲句柄数量,-1 仅表示首次迭代

while (true) {
if (mNextPollTimeoutMillis != 0) {
// 在进入阻塞等待前,刷新所有挂起的 Binder 命令
Binder.flushPendingCommands();
}

// 调用 Native 方法进行轮询。线程可能会在此处阻塞 mNextPollTimeoutMillis 毫秒
nativePollOnce(ptr, mNextPollTimeoutMillis);

// 尝试获取下一条消息(内部会处理同步屏障和时间戳比较)
Message msg = nextMessage(false, false);
if (msg != null) {
msg.markInUse(); // 标记消息正在使用
decAndTraceMessageCount(); // 减少消息计数追踪
return msg; // 成功找到消息,返回给 Looper
}

// 退出保护逻辑:防止 quit()、nativeWake() 和 dispose() 之间产生竞态
if (mWorkerShouldQuit) {
// 设置拆卸标志,等待所有引用释放后销毁指针
setMptrTeardownAndWaitForRefsToDrop();
dispose();
return null;
}

synchronized (mIdleHandlersLock) {
// 如果是第一次进入空闲状态,获取需要运行的空闲任务数量。
// 只有当队列为空,或者队列头部的消息(可能是屏障)还未到处理时间时,才运行 IdleHandler。
if (pendingIdleHandlerCount < 0 && isIdle()) {
pendingIdleHandlerCount = mIdleHandlers.size();
}

if (pendingIdleHandlerCount <= 0) {
// 没有空闲任务需要运行。继续循环并进入阻塞等待。
continue;
}

if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
}

// 运行空闲任务(IdleHandlers)。
// 该代码块在一次 next() 调用中只会执行一次。
for (int i = 0; i < pendingIdleHandlerCount; i++) {
final IdleHandler idler = mPendingIdleHandlers[i];
mPendingIdleHandlers[i] = null; // 释放对句柄的引用

boolean keep = false;
try {
keep = idler.queueIdle(); // 执行空闲任务逻辑
} catch (Throwable t) {
Log.wtf(TAG, "IdleHandler 抛出异常", t);
}

if (!keep) {
// 如果返回 false,则从任务列表中移除该任务
synchronized (mIdleHandlersLock) {
mIdleHandlers.remove(idler);
}
}
}

// 将空闲任务计数重置为 0,确保本次循环不会再次运行它们。
pendingIdleHandlerCount = 0;

// 在调用 IdleHandler 期间,可能已经有新消息送达,
// 因此立即回到循环开头检查消息,且不进入等待。
mNextPollTimeoutMillis = 0;
}
}

/**
* 如果 Looper 当前没有待处理的就绪消息,且未因同步屏障而阻塞,则返回 true。
*
* 此方法可以在任何线程中安全调用。
*
* @return 如果 Looper 处于空闲状态,则返回 true。
*/
public boolean isIdle() {
final long now = SystemClock.uptimeMillis();
return !mStack.hasMessages(sMatchDeliverableMessages, null, -1, null, null, now);
}

/**
* 返回此 Looper 线程当前是否正在轮询(polling)以等待更多任务。
* 这是一个判断循环是否仍然存活(而不是卡在某个回调处理中)的良好信号。
* 请注意,此方法本质上存在竞态条件(racy),因为在你获取结果之前,循环的状态可能已经发生了改变。
*
* 此方法可以在任何线程中安全调用。
*
* @return 如果 Looper 当前正在轮询事件,则返回 true。
* @hide
*/
public boolean isPolling() {
// 如果循环正在退出,则它一定不处于空闲(轮询)状态。
if (!mStack.isQuitting() && incrementMptrRefs()) {
try {
return nativeIsPolling(mPtr);
} finally {
decrementMptrRefs();
}
}
return false;
}

/**
* 返回调度执行时间最晚的消息。
*
*
* 调用者必须确保此方法不会与 Looper 线程的 'next' 操作产生竞态(race)。
* @hide
*/
public @Nullable Message peekLastMessageForTest() {
ActivityThread.throwIfNotInstrumenting();
return mStack.peekLastMessageForTest();
}

/**
* 重置此队列的状态。
*
* @hide
*/
public void resetForTest() {
// 确保当前处于测试(Instrumentation)环境下,否则抛出异常
ActivityThread.throwIfNotInstrumenting();

// 如果此队列已经处于退出状态,我们无法重置其状态并继续使用它,因此直接返回
if (mWorkerShouldQuit) {
return;
}

// 清空所有的空闲任务句柄(IdleHandlers)
synchronized (mIdleHandlersLock) {
mIdleHandlers.clear();
}

// 清空所有注册的文件描述符(File Descriptor)记录
synchronized (mFileDescriptorRecordsLock) {
removeAllFdRecords();
}

// 移除队列中所有的消息
removeAllMessages();

// 清空消息栈的空闲链表(释放缓存的消息对象)
mStack.drainFreelist();

// 重置同步屏障令牌,以反映队列状态的重置。
// 这有助于确保队列的行为在单个测试以及整个测试套件中都是确定的(可预测的)。
resetSyncBarrierTokens();
}

private void removeAllFdRecords() {
if (mFileDescriptorRecords != null) {
while (mFileDescriptorRecords.size() > 0) {
removeOnFileDescriptorEventListener(mFileDescriptorRecords.valueAt(0).mDescriptor);
}
}
}

private void resetSyncBarrierTokens() {
mNextBarrierTokenAtomic.set(1);
mNextBarrierToken = 0;
}

void quit(boolean safe) {
// 如果不允许退出(例如主线程),则抛出异常
if (!mQuitAllowed) {
throw new IllegalStateException("主线程不允许退出。");
}

/*
* TODO: 修复 - 可能会出现这样一种排序:Handler 的 post 操作成功(返回 true)
* 但消息却未能运行。这是因为在各自的操作中可能会读取到不同的时间戳作为“当前时间(now)”,
* 导致退出操作虽然在第一次 CAS(原子更新)中失败了,却观察到了一个更早的时间戳。
*/
long ts = safe ? SystemClock.uptimeMillis() : 0;

// 尝试将队列状态设为“正在退出(Quitting)”
if (mStack.pushQuitting(ts)) {
// 增加引用计数以安全地调用 Native 唤醒方法
if (incrementMptrRefs()) {
try {
// 唤醒处于阻塞状态的 Looper 线程,使其处理退出逻辑
nativeWake(mPtr);
} finally {
// 释放引用计数
decrementMptrRefs();
}
}
}
}

// 下一个屏障令牌。
// 屏障(Barrier)由 target 为 null 的消息表示,其 arg1 字段存放该令牌。
private final AtomicInteger mNextBarrierTokenAtomic = new AtomicInteger(1);

// 出于兼容性原因,必须保留此字段。
@UnsupportedAppUsage
private int mNextBarrierToken;

/**
* 向 Looper 的消息队列投放一个同步屏障。
*
* 在消息队列遇到已投放的同步屏障之前,消息处理照常进行。一旦遇到屏障,
* 队列中后续的“同步消息”将被阻滞(被阻止执行),直到调用 {@link #removeSyncBarrier}
* 并指定标识该屏障的令牌(Token)将其释放为止。
*
* 此方法用于立即推迟所有后续投放的同步消息的执行,直到满足某个释放屏障的条件。
* “异步消息”(参见 {@link Message#isAsynchronous})不受屏障限制,继续照常处理。
*
* 此调用必须始终与具有相同令牌的 {@link #removeSyncBarrier} 调用成对出现,
* 以确保消息队列恢复正常运行。否则,应用程序可能会卡死(Hang)!
*
* @return 唯一标识该屏障的令牌。必须将此令牌传递给 {@link #removeSyncBarrier} 以释放屏障。
*
* @hide
*/
@UnsupportedAppUsage
@TestApi
public int postSyncBarrier() {
long when = SystemClock.uptimeMillis();
final int token = mNextBarrierTokenAtomic.getAndIncrement();

// b/376573804:应用和测试可能会期望能够使用反射(Reflection)来读取此值。
// 应尽力支持这种遗留的使用场景。mNextBarrierToken = token + 1; mNextBarrierToken = token + 1;
final Message msg = Message.obtain();

msg.markInUse();
msg.arg1 = token;

if (!enqueueMessageUnchecked(msg, when)) {
Log.wtf(TAG, "Unexpected error while adding sync barrier!");
return -1;
}

return token;
}

/**
* 移除一个同步屏障。
*
* @param token 由 {@link #postSyncBarrier} 返回的同步屏障令牌。
*
* @throws IllegalStateException 如果找不到该屏障(令牌无效或屏障已被移除)。
*
* @hide
*/
@UnsupportedAppUsage
@TestApi
public void removeSyncBarrier(int token) {
final MatchBarrierToken matchBarrierToken = new MatchBarrierToken(token);

final boolean removed = mStack.moveMatchingToFreelist(matchBarrierToken, null, -1, null,
null, 0);
if (!removed) {
throw new IllegalStateException("The specified message queue synchronization "
+ " barrier token has not been posted or has already been removed.");
}
maybeDrainFreelist();

boolean needWake;
while (true) {
long waitState = mWaitState; // 获取当前的等待状态
long newWaitState;

if (WaitState.isCounter(waitState)) {
// 线程已经处于唤醒状态并正在处理消息
// 将状态更新为计数器自增模式
newWaitState = WaitState.incrementCounter(waitState);
needWake = false; // 无需执行物理唤醒
} else if (!WaitState.hasSyncBarrier(waitState)) {
// 线程处于休眠状态,但并没有在等待同步屏障
// 增加截止时间计数(可能是在调整睡眠时长)
newWaitState = WaitState.incrementDeadline(waitState);
needWake = false; // 同样无需物理唤醒
} else {
// 线程处于休眠状态,(且遇到了屏障等情况),需要立即唤醒
newWaitState = WaitState.initCounter(); // 初始化为计数器状态
needWake = true; // 标记需要执行物理唤醒
}

// 使用 CAS(比较并交换)尝试原子地更新状态
if (sWaitState.compareAndSet(this, waitState, newWaitState)) {
// 更新成功,跳出循环
break;
}
// 如果更新失败(说明状态在此期间被其他线程改变),则继续循环重试
}

if (needWake) {
// 执行唤醒操作,以防 next() 方法正因该屏障而处于休眠状态。
concurrentWake();
}
}

/**
* 获取我们优先级队列中下一条可执行消息的时间戳。
* 如果没有就绪的消息可供分发,则返回 null。

* 调用者必须确保此方法不会与 Looper 线程的 'next' 操作产生竞态(race)。
*/
@SuppressLint("VisiblySynchronized") // Legacy MessageQueue synchronizes on this
Long peekWhenForTest() {
ActivityThread.throwIfNotInstrumenting();
Message ret = nextMessage(true, true);
return ret != null ? ret.when : null;
}

/**
* 返回我们优先级队列中的下一条可执行消息。
*
* 如果没有就绪的消息可供分发,则返回 null。
* 调用者必须确保此方法不会与 Looper 线程的 'next' 操作产生竞态(race)。
*/
@SuppressLint("VisiblySynchronized") // Legacy MessageQueue synchronizes on this
@Nullable
Message pollForTest() {
ActivityThread.throwIfNotInstrumenting();
return nextMessage(false, true);
}

/**
* @return 如果我们当前正因同步屏障(Sync Barrier)而处于阻塞状态,则返回 true。
*
* 对此方法的调用绝对不允许与 next 方法产生竞态(Race)
* 具体而言:在调用此方法之前,必须先暂停 Looper 线程;
* 并且在从该方法返回之前,不得恢复 Looper 线程的运行。
*/
boolean isBlockedOnSyncBarrier() {
ActivityThread.throwIfNotInstrumenting();
// 调用 nextMessage 以处理任何挂起的(同步)屏障
nextMessage(true, false);
Message asyncMsg = mStack.peek(true);

return mSyncBarrier != null &&
(asyncMsg == null || asyncMsg.when <= mSyncBarrier.when);
}

void maybeDrainFreelist() {
if (Thread.currentThread() == mLooperThread) {
mStack.drainFreelist();
}
}

boolean hasMessages(Handler h, int what, Object object) {
if (h == null) {
return false;
}
return mStack.hasMessages(sMatchHandlerWhatAndObject, h, what, object, null, 0);
}

boolean hasEqualMessages(Handler h, int what, Object object) {
if (h == null) {
return false;
}
return mStack.hasMessages(sMatchHandlerWhatAndObjectEquals, h, what, object, null, 0);
}

@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
boolean hasMessages(Handler h, Runnable r, Object object) {
if (h == null) {
return false;
}
return mStack.hasMessages(sMatchHandlerRunnableAndObject, h, -1, object, r, 0);
}

boolean hasMessages(Handler h) {
if (h == null) {
return false;
}
return mStack.hasMessages(sMatchHandler, h, -1, null, null, 0);
}

void removeMessages(Handler h, int what, Object object) {
if (h == null) {
return;
}
mStack.moveMatchingToFreelist(sMatchHandlerWhatAndObject, h, what, object, null, 0);
maybeDrainFreelist();
}

void removeEqualMessages(Handler h, int what, Object object) {
if (h == null) {
return;
}
mStack.moveMatchingToFreelist(sMatchHandlerWhatAndObjectEquals, h, what, object, null, 0);
maybeDrainFreelist();
}

void removeMessages(Handler h, Runnable r, Object object) {
if (h == null || r == null) {
return;
}
mStack.moveMatchingToFreelist(sMatchHandlerRunnableAndObject, h, -1, object, r, 0);
maybeDrainFreelist();
}

void removeEqualMessages(Handler h, Runnable r, Object object) {
if (h == null || r == null) {
return;
}
mStack.moveMatchingToFreelist(sMatchHandlerRunnableAndObjectEquals, h, -1, object, r, 0);
maybeDrainFreelist();
}

void removeCallbacksAndMessages(Handler h, Object object) {
if (h == null) {
return;
}
mStack.moveMatchingToFreelist(sMatchHandlerAndObject, h, -1, object, null, 0);
maybeDrainFreelist();
}

void removeCallbacksAndEqualMessages(Handler h, Object object) {
if (h == null) {
return;
}
mStack.moveMatchingToFreelist(sMatchHandlerAndObjectEquals, h, -1, object, null, 0);
maybeDrainFreelist();
}

private void removeAllMessages() {
mStack.moveMatchingToFreelist(sMatchAllMessages, null, -1, null, null, 0);
maybeDrainFreelist();
}

private void removeAllFutureMessages(long when) {
mStack.moveMatchingToFreelist(sMatchAllFutureMessages, null, -1, null, null, when);
maybeDrainFreelist();
}

/**
* 发现线程何时将要阻塞并等待更多消息的回调接口。
*/
public static interface IdleHandler {
/**
* 当消息队列已处理完所有消息并即将开始等待新消息时调用。
* * 返回 true 以保持此 IdleHandler 继续生效;
* 返回 false 则在执行后将其移除。
* * 注意:如果队列中仍有待处理的消息,但这些消息都排定在当前时间之后分发(即尚未到期),
* 此方法也可能会被调用。
*/
boolean queueIdle();
}

/**
* 向此消息队列添加一个新的 {@link IdleHandler}。
* * 您可以通过在 {@link IdleHandler#queueIdle IdleHandler.queueIdle()} 被触发时返回 false
* 来让系统自动为您移除它,也可以通过 {@link #removeIdleHandler} 显式地将其移除。
*
* <p>此方法可以在任何线程中安全调用。
*
* @param handler 要添加的 IdleHandler。
*/
public void addIdleHandler(@NonNull IdleHandler handler) {
if (handler == null) {
throw new NullPointerException("不能添加空的 IdleHandler");
}
synchronized (mIdleHandlersLock) {
// 将 handler 添加到空闲任务列表中
mIdleHandlers.add(handler);
}
}

/**
* 从队列中移除之前通过 {@link #addIdleHandler} 添加的 {@link IdleHandler}。
* 如果指定的对象当前不在空闲列表中,则不执行任何操作。
*
* <p>此方法可以在任何线程中安全调用。
*
* @param handler 要移除的 IdleHandler。
*/
public void removeIdleHandler(@NonNull IdleHandler handler) {
synchronized (mIdleHandlersLock) {
// 从空闲任务列表中移除指定的 handler
mIdleHandlers.remove(handler);
}
}

/**
* 当文件描述符相关事件发生时被调用的监听器接口。
*/
public interface OnFileDescriptorEventListener {
/**
* 文件描述符事件:表明文件描述符已就绪,可以进行输入操作(如读取)。
* <p>
* 监听器应当从文件描述符中读取所有可用数据,
* 然后返回 <code>true</code> 以保持监听器活跃,或返回 <code>false</code> 以移除监听器。
* </p><p>
* 对于 Socket 而言,此事件可能表示至少有一个传入连接等待监听器执行 accept 操作。
* </p><p>
* 只有在添加监听器时指定了 {@link #EVENT_INPUT} 事件掩码,才会触发此事件。
* </p>
*/
public static final int EVENT_INPUT = 1 << 0;

/**
* 文件描述符事件:表明文件描述符已就绪,可以进行输出操作(如写入)。
* <p>
* 监听器应当根据需要写入尽可能多的数据。如果无法一次性完成写入,
* 则应返回 <code>true</code> 以保持监听器活跃。否则,应返回 <code>false</code>
* 以移除监听器,待下次需要写入数据时再重新注册。
* </p><p>
* 只有在添加监听器时指定了 {@link #EVENT_OUTPUT} 事件掩码,才会触发此事件。
* </p>
*/
public static final int EVENT_OUTPUT = 1 << 1;

/**
* 文件描述符事件:表明文件描述符遇到了致命错误。
* <p>
* 文件描述符错误可能由于多种原因产生。一种常见的错误是
* Socket 或管道的远程端关闭了连接。
* </p><p>
* 无论添加监听器时是否指定了 {@link #EVENT_ERROR} 事件掩码,该事件都可能随时触发。
* </p>
*/
public static final int EVENT_ERROR = 1 << 2;

/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(flag = true, prefix = { "EVENT_" }, value = {
EVENT_INPUT,
EVENT_OUTPUT,
EVENT_ERROR
})
public @interface Events {}

/**
* 当文件描述符接收到事件时调用。
*
* @param fd 文件描述符。
* @param events 发生的事件集合:{@link #EVENT_INPUT}、{@link #EVENT_OUTPUT}
* 和 {@link #EVENT_ERROR} 事件掩码的组合。
* @return 接下来想要继续监听的新事件集合,若返回 0 则表示注销该监听器。
*
* @see #EVENT_INPUT
* @see #EVENT_OUTPUT
* @see #EVENT_ERROR
*/
@Events int onFileDescriptorEvents(@NonNull FileDescriptor fd, @Events int events);
}

static final class FileDescriptorRecord {
public final FileDescriptor mDescriptor;
public int mEvents;
public OnFileDescriptorEventListener mListener;
public int mSeq;

public FileDescriptorRecord(FileDescriptor descriptor,
int events, OnFileDescriptorEventListener listener) {
mDescriptor = descriptor;
mEvents = events;
mListener = listener;
}
}

/**
* 添加一个文件描述符监听器,以便在文件描述符相关事件发生时接收通知。
* <p>
* 如果该文件描述符已经注册过,则指定的事件和监听器将替换之前与之关联的任何设置。
* 每个文件描述符只能设置一个监听器。
* </p><p>
* 当文件描述符不再使用时,务必始终注销监听器,这一点至关重要。
* </p>
*
* @param fd 欲注册监听器的文件描述符。
* @param events 欲接收的事件集合:{@link OnFileDescriptorEventListener#EVENT_INPUT}、
* {@link OnFileDescriptorEventListener#EVENT_OUTPUT} 和 {@link OnFileDescriptorEventListener#EVENT_ERROR}
* 事件掩码的组合。如果请求的事件集合为 0,则注销该监听器。
* @param listener 当文件描述符事件发生时要触发的监听器。
*
* @see OnFileDescriptorEventListener
* @see #removeOnFileDescriptorEventListener
*/
@RavenwoodThrow(blockedBy = android.os.ParcelFileDescriptor.class)
public void addOnFileDescriptorEventListener(@NonNull FileDescriptor fd,
@OnFileDescriptorEventListener.Events int events,
@NonNull OnFileDescriptorEventListener listener) {
if (fd == null) {
throw new IllegalArgumentException("fd 不能为空");
}
if (listener == null) {
throw new IllegalArgumentException("listener 不能为空");
}

synchronized (mFileDescriptorRecordsLock) {
// 在持有锁的情况下更新或添加 FD 记录
updateOnFileDescriptorEventListenerLocked(fd, events, listener);
}
}

/**
* 移除一个文件描述符监听器。
* <p>
* 如果指定的文件描述符尚未注册任何监听器,则此方法不执行任何操作。
* </p>
*
* @param fd 欲注销监听器的文件描述符。
*
* @see OnFileDescriptorEventListener
* @see #addOnFileDescriptorEventListener
*/
@RavenwoodThrow(blockedBy = android.os.ParcelFileDescriptor.class)
public void removeOnFileDescriptorEventListener(@NonNull FileDescriptor fd) {
if (fd == null) {
throw new IllegalArgumentException("fd 不能为空");
}
synchronized (mFileDescriptorRecordsLock) {
// 通过传入 0 和 null,利用更新逻辑来移除现有的 FD 记录
updateOnFileDescriptorEventListenerLocked(fd, 0, null);
}
}

private void setFileDescriptorEvents(int fdNum, int events) {
if (incrementMptrRefs()) {
try {
nativeSetFileDescriptorEvents(mPtr, fdNum, events);
} finally {
decrementMptrRefs();
}
}
}

@RavenwoodThrow(blockedBy = android.os.ParcelFileDescriptor.class)
private void updateOnFileDescriptorEventListenerLocked(FileDescriptor fd, int events,
OnFileDescriptorEventListener listener) {
final int fdNum = fd.getInt$();

int index = -1;
FileDescriptorRecord record = null;
if (mFileDescriptorRecords != null) {
index = mFileDescriptorRecords.indexOfKey(fdNum);
if (index >= 0) {
record = mFileDescriptorRecords.valueAt(index);
if (record != null && record.mEvents == events) {
return;
}
}
}

if (events != 0) {
events |= OnFileDescriptorEventListener.EVENT_ERROR;
if (record == null) {
if (mFileDescriptorRecords == null) {
mFileDescriptorRecords = new SparseArray<FileDescriptorRecord>();
}
record = new FileDescriptorRecord(fd, events, listener);
mFileDescriptorRecords.put(fdNum, record);
} else {
record.mListener = listener;
record.mEvents = events;
record.mSeq += 1;
}
setFileDescriptorEvents(fdNum, events);
} else if (record != null) {
record.mEvents = 0;
mFileDescriptorRecords.removeAt(index);

setFileDescriptorEvents(fdNum, 0);
}
}

// 由 Native 代码调用。
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
private int dispatchEvents(int fd, int events) {
// 获取文件描述符记录以及任何可能发生变化的状态。
final FileDescriptorRecord record;
final int oldWatchedEvents;
final OnFileDescriptorEventListener listener;
final int seq;

synchronized (mFileDescriptorRecordsLock) {
// 从集合中查找该 FD 对应的记录
record = mFileDescriptorRecords.get(fd);
if (record == null) {
return 0; // 虚假唤醒:没有注册监听器
}

oldWatchedEvents = record.mEvents;
// 根据当前正在监听的集合过滤收到的事件
events &= oldWatchedEvents;
if (events == 0) {
return oldWatchedEvents; // 虚假唤醒:监听的事件集合已更改
}

listener = record.mListener;
seq = record.mSeq; // 获取序列号,用于后续验证记录是否被重新定义过
}

// 在锁之外调用监听器,避免在回调执行期间长时间占用锁导致死锁或阻塞
int newWatchedEvents = listener.onFileDescriptorEvents(
record.mDescriptor, events);

// 如果监听器返回了非 0 的新事件集合,强制加上错误事件监听(EVENT_ERROR 始终需要关注)
if (newWatchedEvents != 0) {
newWatchedEvents |= OnFileDescriptorEventListener.EVENT_ERROR;
}

// 如果监听器改变了想要监听的事件集合,且在此期间该记录没有被其他线程更新过,
// 则更新文件描述符记录。
if (newWatchedEvents != oldWatchedEvents) {
synchronized (mFileDescriptorRecordsLock) {
int index = mFileDescriptorRecords.indexOfKey(fd);
// 确保记录依然存在,且没有被重新注册(通过比较 record 对象引用和序列号 seq)
if (index >= 0 && mFileDescriptorRecords.valueAt(index) == record
&& record.mSeq == seq) {
record.mEvents = newWatchedEvents;
if (newWatchedEvents == 0) {
// 如果不再监听任何事件,则移除该记录
mFileDescriptorRecords.removeAt(index);
}
}
}
}

// 返回新的监听事件集合,供 Native 代码据此更新 epoll 监听状态。
return newWatchedEvents;
}

private void decAndTraceMessageCount() {
mMessageCount.decrementAndGet();
if (PerfettoTrace.isMQCategoryEnabled()) {
traceMessageCount();
}
}

@NeverCompile
void dump(Printer pw, String prefix, Handler h) {
pw.println(prefix + "(MessageQueue is using DeliQueue implementation)");
final int n = mStack.dump(pw, prefix, h);
pw.println(prefix + "(Total messages: " + n + ", polling=" + isPolling()
+ ", quitting=" + mStack.isQuitting() + ")");
}

@NeverCompile
void dumpDebug(ProtoOutputStream proto, long fieldId) {
final long messageQueueToken = proto.start(fieldId);
mStack.dumpDebug(proto);
proto.write(MessageQueueProto.IS_POLLING_LOCKED, isPolling());
proto.write(MessageQueueProto.IS_QUITTING, mStack.isQuitting());
proto.end(messageQueueToken);
}

private void incAndTraceMessageCount(Message msg, long when) {
mMessageCount.incrementAndGet();
if (PerfettoTrace.isMQCategoryEnabled()) {
msg.sendingThreadName = Thread.currentThread().getName();
final long eventId = msg.eventId = PerfettoTrace.getFlowId();

traceMessageCount();
final long messageDelayMs = Math.max(0L, when - SystemClock.uptimeMillis());
if (PerfettoTrace.IS_USE_SDK_TRACING_API_V3) {
// 使用新版(V3)SDK 记录名为 "message_queue_send" 的事件
com.android.internal.dev.perfetto.sdk.PerfettoTrace.instant(
PerfettoTrace.MQ_CATEGORY_V3, "message_queue_send")
.setFlow(eventId) // 关联 Flow ID
.beginProto() // 开始以 Protobuf 格式构建自定义数据
.beginNested(2004 /* message_queue */) // 嵌套 MQ 相关的元数据字段
.addField(2 /* 接收线程名称 */, mThreadName)
.addField(3 /* 消息标识 (what) */, msg.what)
.addField(4 /* 预计延迟时间 (ms) */, messageDelayMs)
.endNested()
.endProto()
.emit(); // 发射事件到系统追踪缓冲区
} else {
// 使用旧版 SDK 执行相同的记录逻辑
PerfettoTrace.instant(PerfettoTrace.MQ_CATEGORY, "message_queue_send")
.setFlow(eventId)
.beginProto()
.beginNested(2004 /* message_queue */)
.addField(2 /* 接收线程名称 */, mThreadName)
.addField(3 /* 消息标识 (what) */, msg.what)
.addField(4 /* 预计延迟时间 (ms) */, messageDelayMs)
.endNested()
.endProto()
.emit();
}
}
}

private void traceMessageCount() {
if (PerfettoTrace.IS_USE_SDK_TRACING_API_V3) {
com.android.internal.dev.perfetto.sdk.PerfettoTrace.counter(
PerfettoTrace.MQ_CATEGORY_V3, mMessageCount.get())
.usingThreadCounterTrack(mTid, mThreadName)
.emit();
} else {
PerfettoTrace.counter(PerfettoTrace.MQ_CATEGORY, mMessageCount.get())
.usingThreadCounterTrack(mTid, mThreadName)
.emit();
}
}
}
, ,