diff options
| author | 2024-12-07 00:54:11 +0000 | |
|---|---|---|
| committer | 2024-12-10 00:54:42 +0000 | |
| commit | c338cb3db9bd41c3a8e53f3bed33265eba0348cc (patch) | |
| tree | 13a017248d5d67da35eaab15955960ec483b7cbd | |
| parent | 09429c7d24cc423d4fe99dad6fe2c92bf3ec2a30 (diff) | |
MessageQueue.isBlockedOnSyncBarrier() fixes
- add some missing checks for null references
- we need to flush our trieber stack before checking
for deliverable messages
- mirror the changes into ConcurrentMessageQueue
- also add some compile fixes to ConcurrentMessageQueue
Test: atest TestLooperManagerTest
Bug: 379472827
Flag: android.os.message_queue_testability
Change-Id: I1072117781ffe7765fb9c8f51b39f09829b8435f
3 files changed, 28 insertions, 15 deletions
diff --git a/core/java/android/os/CombinedMessageQueue/MessageQueue.java b/core/java/android/os/CombinedMessageQueue/MessageQueue.java index b509c7a441d3..230fa3fec930 100644 --- a/core/java/android/os/CombinedMessageQueue/MessageQueue.java +++ b/core/java/android/os/CombinedMessageQueue/MessageQueue.java @@ -1355,14 +1355,21 @@ public final class MessageQueue { /** * @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(); if (mUseConcurrent) { + // Call nextMessage to get the stack drained into our priority queues + nextMessage(true); + Iterator<MessageNode> queueIter = mPriorityQueue.iterator(); MessageNode queueNode = iterateNext(queueIter); - if (queueNode.isBarrier()) { + if (queueNode != null && queueNode.isBarrier()) { long now = SystemClock.uptimeMillis(); /* Look for a deliverable async node. If one exists we are not blocked. */ @@ -1375,14 +1382,12 @@ public final class MessageQueue { * Look for a deliverable sync node. In this case, if one exists we are blocked * since the barrier prevents delivery of the Message. */ - while (queueNode.isBarrier()) { + while (queueNode != null && queueNode.isBarrier()) { queueNode = iterateNext(queueIter); } if (queueNode != null && now >= queueNode.getWhen()) { return true; } - - return false; } } else { Message msg = mMessages; @@ -1409,10 +1414,8 @@ public final class MessageQueue { if (iter != null && now >= iter.when) { return true; } - return false; } } - /* No barrier was found. */ return false; } diff --git a/core/java/android/os/ConcurrentMessageQueue/MessageQueue.java b/core/java/android/os/ConcurrentMessageQueue/MessageQueue.java index de0259eb1e36..d7d8e4199b33 100644 --- a/core/java/android/os/ConcurrentMessageQueue/MessageQueue.java +++ b/core/java/android/os/ConcurrentMessageQueue/MessageQueue.java @@ -19,6 +19,7 @@ package android.os; import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.TestApi; import android.app.ActivityThread; import android.app.Instrumentation; @@ -784,7 +785,7 @@ public final class MessageQueue { mMessageDirectlyQueued = false; nativePollOnce(ptr, mNextPollTimeoutMillis); - Message msg = nextMessage(); + Message msg = nextMessage(false); if (msg != null) { msg.markInUse(); return msg; @@ -1087,7 +1088,6 @@ public final class MessageQueue { * * 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 = nextMessage(true); @@ -1100,7 +1100,6 @@ public final class MessageQueue { * * Caller must ensure that this doesn't race 'next' from the Looper thread. */ - @SuppressLint("VisiblySynchronized") // Legacy MessageQueue synchronizes on this @Nullable Message pollForTest() { throwIfNotTest(); @@ -1109,13 +1108,21 @@ public final class MessageQueue { /** * @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(); + + // Call nextMessage to get the stack drained into our priority queues + nextMessage(true); + Iterator<MessageNode> queueIter = mPriorityQueue.iterator(); MessageNode queueNode = iterateNext(queueIter); - if (queueNode.isBarrier()) { + if (queueNode != null && queueNode.isBarrier()) { long now = SystemClock.uptimeMillis(); /* Look for a deliverable async node. If one exists we are not blocked. */ @@ -1128,15 +1135,14 @@ public final class MessageQueue { * Look for a deliverable sync node. In this case, if one exists we are blocked * since the barrier prevents delivery of the Message. */ - while (queueNode.isBarrier()) { + while (queueNode != null && queueNode.isBarrier()) { queueNode = iterateNext(queueIter); } if (queueNode != null && now >= queueNode.getWhen()) { return true; } - - return false; } + return false; } private StateNode getStateNode(StackNode node) { @@ -1193,7 +1199,7 @@ public final class MessageQueue { MessageNode p = (MessageNode) top; while (true) { - if (compare.compareMessage(p.mMessage, h, what, object, r, when)) { + if (compare.compareMessage(p, h, what, object, r, when)) { found = true; if (DEBUG) { Log.w(TAG, "stackHasMessages node matches"); @@ -1238,7 +1244,7 @@ public final class MessageQueue { while (iterator.hasNext()) { MessageNode msg = iterator.next(); - if (compare.compareMessage(msg.mMessage, h, what, object, r, when)) { + if (compare.compareMessage(msg, h, what, object, r, when)) { if (removeMatches) { found = true; if (queue.remove(msg)) { diff --git a/core/java/android/os/LegacyMessageQueue/MessageQueue.java b/core/java/android/os/LegacyMessageQueue/MessageQueue.java index 5e1e1fdca5c8..c0333e914b4d 100644 --- a/core/java/android/os/LegacyMessageQueue/MessageQueue.java +++ b/core/java/android/os/LegacyMessageQueue/MessageQueue.java @@ -814,6 +814,10 @@ public final class MessageQueue { /** * @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(); |