diff --git a/services/core/java/com/android/server/am/BroadcastProcessQueue.java b/services/core/java/com/android/server/am/BroadcastProcessQueue.java index c26fd5d9b7981dcbbca1985409d8e0bbb8e5bcc3..3ab978080d853e2e100472efdd84fa2301a030be 100644 --- a/services/core/java/com/android/server/am/BroadcastProcessQueue.java +++ b/services/core/java/com/android/server/am/BroadcastProcessQueue.java @@ -264,6 +264,11 @@ class BroadcastProcessQueue { && record.getDeliveryGroupPolicy() == BroadcastOptions.DELIVERY_GROUP_POLICY_ALL) { final BroadcastRecord replacedBroadcastRecord = replaceBroadcast(record, recordIndex); if (replacedBroadcastRecord != null) { + if (mLastDeferredStates && shouldBeDeferred() + && (record.getDeliveryState(recordIndex) + == BroadcastRecord.DELIVERY_PENDING)) { + deferredStatesApplyConsumer.accept(record, recordIndex); + } return replacedBroadcastRecord; } } 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 e91472670c2d4a37ef49e197bcfc72695b0b0f56..28a5864f454b6e3f99c10590faac248eee453dc0 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java @@ -1801,6 +1801,59 @@ public class BroadcastQueueTest extends BaseBroadcastQueueTest { verifyScheduleRegisteredReceiver(never(), receiverYellowApp, airplane); } + @Test + public void testReplacePendingToCachedProcess_withDeferrableBroadcast() throws Exception { + // Legacy stack doesn't support deferral + Assume.assumeTrue(mImpl == Impl.MODERN); + + final ProcessRecord callerApp = makeActiveProcessRecord(PACKAGE_RED); + final ProcessRecord receiverGreenApp = makeActiveProcessRecord(PACKAGE_GREEN); + final ProcessRecord receiverBlueApp = makeActiveProcessRecord(PACKAGE_BLUE); + final ProcessRecord receiverYellowApp = makeActiveProcessRecord(PACKAGE_YELLOW); + + setProcessFreezable(receiverGreenApp, true, false); + mQueue.onProcessFreezableChangedLocked(receiverGreenApp); + waitForIdle(); + + final Intent timeTick = new Intent(Intent.ACTION_TIME_TICK) + .addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); + final BroadcastOptions opts = BroadcastOptions.makeBasic() + .setDeferralPolicy(BroadcastOptions.DEFERRAL_POLICY_UNTIL_ACTIVE); + + final BroadcastFilter receiverGreen = makeRegisteredReceiver(receiverGreenApp, 10); + final BroadcastFilter receiverBlue = makeRegisteredReceiver(receiverBlueApp, 5); + final BroadcastFilter receiverYellow = makeRegisteredReceiver(receiverYellowApp, 0); + enqueueBroadcast(makeBroadcastRecord(timeTick, callerApp, opts, List.of( + receiverGreen, receiverBlue, receiverYellow))); + + // Enqueue the broadcast again to replace the earlier one + enqueueBroadcast(makeBroadcastRecord(timeTick, callerApp, opts, List.of( + receiverGreen, receiverBlue, receiverYellow))); + + waitForIdle(); + // Green should still be in the cached state and shouldn't receive the broadcast + verifyScheduleRegisteredReceiver(never(), receiverGreenApp, timeTick); + + final IApplicationThread blueThread = receiverBlueApp.getThread(); + final IApplicationThread yellowThread = receiverYellowApp.getThread(); + final InOrder inOrder = inOrder(blueThread, yellowThread); + inOrder.verify(blueThread).scheduleRegisteredReceiver( + any(), argThat(filterEqualsIgnoringComponent(timeTick)), + anyInt(), any(), any(), anyBoolean(), anyBoolean(), anyBoolean(), + eq(UserHandle.USER_SYSTEM), anyInt(), anyInt(), any()); + inOrder.verify(yellowThread).scheduleRegisteredReceiver( + any(), argThat(filterEqualsIgnoringComponent(timeTick)), + anyInt(), any(), any(), anyBoolean(), anyBoolean(), anyBoolean(), + eq(UserHandle.USER_SYSTEM), anyInt(), anyInt(), any()); + + setProcessFreezable(receiverGreenApp, false, false); + mQueue.onProcessFreezableChangedLocked(receiverGreenApp); + waitForIdle(); + + // Confirm that green receives the broadcast once it comes out of the cached state + verifyScheduleRegisteredReceiver(times(1), receiverGreenApp, timeTick); + } + @Test public void testIdleAndBarrier() throws Exception { final ProcessRecord callerApp = makeActiveProcessRecord(PACKAGE_RED);