diff --git a/services/core/java/com/android/server/am/BroadcastProcessQueue.java b/services/core/java/com/android/server/am/BroadcastProcessQueue.java index 0b5b1cb2902e1..4b6d32427d684 100644 --- a/services/core/java/com/android/server/am/BroadcastProcessQueue.java +++ b/services/core/java/com/android/server/am/BroadcastProcessQueue.java @@ -25,6 +25,7 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UptimeMillisLong; +import android.app.BroadcastOptions; import android.content.Intent; import android.content.pm.ResolveInfo; import android.os.SystemClock; @@ -257,7 +258,10 @@ class BroadcastProcessQueue { deferredStatesApplyConsumer.accept(record, recordIndex); } - if (record.isReplacePending()) { + // Ignore FLAG_RECEIVER_REPLACE_PENDING if the sender specified the policy using the + // BroadcastOptions delivery group APIs. + if (record.isReplacePending() + && record.getDeliveryGroupPolicy() == BroadcastOptions.DELIVERY_GROUP_POLICY_ALL) { final BroadcastRecord replacedBroadcastRecord = replaceBroadcast(record, recordIndex); if (replacedBroadcastRecord != null) { return replacedBroadcastRecord; diff --git a/services/core/java/com/android/server/am/BroadcastQueueImpl.java b/services/core/java/com/android/server/am/BroadcastQueueImpl.java index f6004d7d2b7fb..c6165cd3220e7 100644 --- a/services/core/java/com/android/server/am/BroadcastQueueImpl.java +++ b/services/core/java/com/android/server/am/BroadcastQueueImpl.java @@ -339,7 +339,7 @@ public class BroadcastQueueImpl extends BroadcastQueue { private BroadcastRecord replaceBroadcastLocked(ArrayList queue, BroadcastRecord r, String typeForLogging) { final Intent intent = r.intent; - for (int i = queue.size() - 1; i > 0; i--) { + for (int i = queue.size() - 1; i >= 0; i--) { final BroadcastRecord old = queue.get(i); if (old.userId == r.userId && intent.filterEquals(old.intent)) { if (DEBUG_BROADCAST) { diff --git a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java index cbc75401f0b86..93fb91ab8cdda 100644 --- a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java +++ b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java @@ -719,11 +719,12 @@ class BroadcastQueueModernImpl extends BroadcastQueue { private void skipAndCancelReplacedBroadcasts(ArraySet replacedBroadcasts) { for (int i = 0; i < replacedBroadcasts.size(); ++i) { final BroadcastRecord r = replacedBroadcasts.valueAt(i); - r.resultCode = Activity.RESULT_CANCELED; - r.resultData = null; - r.resultExtras = null; - scheduleResultTo(r); - notifyFinishBroadcast(r); + // Skip all the receivers in the replaced broadcast + for (int rcvrIdx = 0; rcvrIdx < r.receivers.size(); ++rcvrIdx) { + if (!isDeliveryStateTerminal(r.getDeliveryState(rcvrIdx))) { + mBroadcastConsumerSkipAndCanceled.accept(r, rcvrIdx); + } + } } } diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java index 4989f841a275b..03231ecfb723b 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java @@ -1903,6 +1903,34 @@ public class BroadcastQueueTest { anyInt(), anyInt(), any()); } + @Test + public void testReplacePending_diffReceivers() throws Exception { + final ProcessRecord callerApp = makeActiveProcessRecord(PACKAGE_RED); + final ProcessRecord receiverGreenApp = makeActiveProcessRecord(PACKAGE_GREEN); + final ProcessRecord receiverBlueApp = makeActiveProcessRecord(PACKAGE_BLUE); + final ProcessRecord receiverYellowApp = makeActiveProcessRecord(PACKAGE_YELLOW); + final BroadcastFilter receiverGreen = makeRegisteredReceiver(receiverGreenApp); + final BroadcastFilter receiverBlue = makeRegisteredReceiver(receiverBlueApp); + final BroadcastFilter receiverYellow = makeRegisteredReceiver(receiverYellowApp); + + final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED) + .addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); + + enqueueBroadcast(makeBroadcastRecord(airplane, callerApp, List.of( + withPriority(receiverGreen, 10), + withPriority(receiverBlue, 5), + withPriority(receiverYellow, 0)))); + enqueueBroadcast(makeBroadcastRecord(airplane, callerApp, List.of( + withPriority(receiverGreen, 10), + withPriority(receiverBlue, 5)))); + + waitForIdle(); + + verifyScheduleRegisteredReceiver(times(1), receiverGreenApp, airplane); + verifyScheduleRegisteredReceiver(times(1), receiverBlueApp, airplane); + verifyScheduleRegisteredReceiver(never(), receiverYellowApp, airplane); + } + @Test public void testIdleAndBarrier() throws Exception { final ProcessRecord callerApp = makeActiveProcessRecord(PACKAGE_RED);