Loading services/core/java/com/android/server/am/BroadcastProcessQueue.java +2 −0 Original line number Diff line number Diff line Loading @@ -385,9 +385,11 @@ class BroadcastProcessQueue { public void setProcess(@Nullable ProcessRecord app) { this.app = app; if (app != null) { setProcessCached(app.isCached()); setProcessInstrumented(app.getActiveInstrumentation() != null); setProcessPersistent(app.isPersistent()); } else { setProcessCached(false); setProcessInstrumented(false); setProcessPersistent(false); } Loading services/core/java/com/android/server/am/BroadcastQueueModernImpl.java +3 −1 Original line number Diff line number Diff line Loading @@ -1328,7 +1328,9 @@ class BroadcastQueueModernImpl extends BroadcastQueue { synchronized (mService) { BroadcastProcessQueue leaf = mProcessQueues.get(uid); while (leaf != null) { leaf.setProcessCached(cached); // Update internal state by refreshing values previously // read from any known running process leaf.setProcess(leaf.app); updateQueueDeferred(leaf); updateRunnableList(leaf); leaf = leaf.processNameNext; Loading services/core/java/com/android/server/am/ProcessRecord.java +6 −0 Original line number Diff line number Diff line Loading @@ -1039,7 +1039,13 @@ class ProcessRecord implements WindowProcessListener { mInFullBackup = inFullBackup; } @GuardedBy("mService") public void setCached(boolean cached) { mState.setCached(cached); } @Override @GuardedBy("mService") public boolean isCached() { return mState.isCached(); } Loading services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java +72 −3 Original line number Diff line number Diff line Loading @@ -53,6 +53,7 @@ import android.app.AppOpsManager; import android.app.BackgroundStartPrivileges; import android.app.BroadcastOptions; import android.app.IApplicationThread; import android.app.UidObserver; import android.app.usage.UsageEvents.Event; import android.app.usage.UsageStatsManagerInternal; import android.content.ComponentName; Loading Loading @@ -83,6 +84,7 @@ import android.util.proto.ProtoOutputStream; import androidx.test.filters.MediumTest; import androidx.test.platform.app.InstrumentationRegistry; import com.android.server.AlarmManagerInternal; import com.android.server.DropBoxManagerInternal; import com.android.server.LocalServices; import com.android.server.am.ActivityManagerService.Injector; Loading Loading @@ -153,11 +155,14 @@ public class BroadcastQueueTest { private PackageManagerInternal mPackageManagerInt; @Mock private UsageStatsManagerInternal mUsageStatsManagerInt; @Mock private AlarmManagerInternal mAlarmManagerInt; private ActivityManagerService mAms; private BroadcastQueue mQueue; BroadcastConstants mConstants; private BroadcastSkipPolicy mSkipPolicy; private UidObserver mUidObserver; /** * Desired behavior of the next Loading Loading @@ -204,6 +209,8 @@ public class BroadcastQueueTest { LocalServices.addService(DropBoxManagerInternal.class, mDropBoxManagerInt); LocalServices.removeServiceForTest(PackageManagerInternal.class); LocalServices.addService(PackageManagerInternal.class, mPackageManagerInt); LocalServices.removeServiceForTest(AlarmManagerInternal.class); LocalServices.addService(AlarmManagerInternal.class, mAlarmManagerInt); doReturn(new ComponentName("", "")).when(mPackageManagerInt).getSystemUiServiceComponent(); doNothing().when(mPackageManagerInt).setPackageStoppedState(any(), anyBoolean(), anyInt()); doAnswer((invocation) -> { Loading Loading @@ -281,6 +288,11 @@ public class BroadcastQueueTest { }).when(mAms).getProcessRecordLocked(any(), anyInt()); doNothing().when(mAms).appNotResponding(any(), any()); doAnswer((invocation) -> { mUidObserver = invocation.getArgument(0); return null; }).when(mAms).registerUidObserver(any(), anyInt(), anyInt(), any()); mConstants = new BroadcastConstants(Settings.Global.BROADCAST_FG_CONSTANTS); mConstants.TIMEOUT = 100; mConstants.ALLOW_BG_ACTIVITY_START_TIMEOUT = 0; Loading @@ -305,6 +317,8 @@ public class BroadcastQueueTest { } else { throw new UnsupportedOperationException(); } mQueue.start(mContext.getContentResolver()); } @After Loading Loading @@ -683,12 +697,22 @@ public class BroadcastQueueTest { anyInt(), anyInt(), any()); } private void verifyScheduleRegisteredReceiver(ProcessRecord app, private void verifyScheduleRegisteredReceiver(ProcessRecord app, Intent intent) throws Exception { verifyScheduleRegisteredReceiver(times(1), app, intent, UserHandle.USER_SYSTEM); } private void verifyScheduleRegisteredReceiver(VerificationMode mode, ProcessRecord app, Intent intent) throws Exception { verify(app.getThread()).scheduleRegisteredReceiver( verifyScheduleRegisteredReceiver(mode, app, intent, UserHandle.USER_SYSTEM); } private void verifyScheduleRegisteredReceiver(VerificationMode mode, ProcessRecord app, Intent intent, int userId) throws Exception { verify(app.getThread(), mode).scheduleRegisteredReceiver( any(), argThat(filterEqualsIgnoringComponent(intent)), anyInt(), any(), any(), anyBoolean(), anyBoolean(), anyBoolean(), eq(UserHandle.USER_SYSTEM), anyInt(), anyInt(), any()); eq(userId), anyInt(), anyInt(), any()); } private void verifyScheduleRegisteredReceiver(VerificationMode mode, ProcessRecord app, Loading Loading @@ -1934,4 +1958,49 @@ public class BroadcastQueueTest { getUidForPackage(PACKAGE_ORANGE)); assertNull(receiverOrangeApp); } /** * Verify broadcasts to runtime receivers in cached processes are deferred * until that process leaves the cached state. */ @Test public void testDeferralPolicy_UntilActive() 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); receiverGreenApp.setCached(true); receiverBlueApp.setCached(true); receiverYellowApp.setCached(false); final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED); final BroadcastOptions opts = BroadcastOptions.makeBasic() .setDeferralPolicy(BroadcastOptions.DEFERRAL_POLICY_UNTIL_ACTIVE); enqueueBroadcast(makeBroadcastRecord(airplane, callerApp, opts, List.of(makeRegisteredReceiver(receiverGreenApp), makeRegisteredReceiver(receiverBlueApp), makeManifestReceiver(PACKAGE_BLUE, CLASS_BLUE), makeRegisteredReceiver(receiverYellowApp)))); waitForIdle(); // Green ignored since it's in cached state verifyScheduleRegisteredReceiver(never(), receiverGreenApp, airplane); // Blue delivered both since it has a manifest receiver verifyScheduleReceiver(times(1), receiverBlueApp, airplane); verifyScheduleRegisteredReceiver(times(1), receiverBlueApp, airplane); // Yellow delivered since it's not cached verifyScheduleRegisteredReceiver(times(1), receiverYellowApp, airplane); // Shift green to be active and confirm that deferred broadcast is delivered receiverGreenApp.setCached(false); mUidObserver.onUidCachedChanged(getUidForPackage(PACKAGE_GREEN), false); waitForIdle(); verifyScheduleRegisteredReceiver(times(1), receiverGreenApp, airplane); } } Loading
services/core/java/com/android/server/am/BroadcastProcessQueue.java +2 −0 Original line number Diff line number Diff line Loading @@ -385,9 +385,11 @@ class BroadcastProcessQueue { public void setProcess(@Nullable ProcessRecord app) { this.app = app; if (app != null) { setProcessCached(app.isCached()); setProcessInstrumented(app.getActiveInstrumentation() != null); setProcessPersistent(app.isPersistent()); } else { setProcessCached(false); setProcessInstrumented(false); setProcessPersistent(false); } Loading
services/core/java/com/android/server/am/BroadcastQueueModernImpl.java +3 −1 Original line number Diff line number Diff line Loading @@ -1328,7 +1328,9 @@ class BroadcastQueueModernImpl extends BroadcastQueue { synchronized (mService) { BroadcastProcessQueue leaf = mProcessQueues.get(uid); while (leaf != null) { leaf.setProcessCached(cached); // Update internal state by refreshing values previously // read from any known running process leaf.setProcess(leaf.app); updateQueueDeferred(leaf); updateRunnableList(leaf); leaf = leaf.processNameNext; Loading
services/core/java/com/android/server/am/ProcessRecord.java +6 −0 Original line number Diff line number Diff line Loading @@ -1039,7 +1039,13 @@ class ProcessRecord implements WindowProcessListener { mInFullBackup = inFullBackup; } @GuardedBy("mService") public void setCached(boolean cached) { mState.setCached(cached); } @Override @GuardedBy("mService") public boolean isCached() { return mState.isCached(); } Loading
services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java +72 −3 Original line number Diff line number Diff line Loading @@ -53,6 +53,7 @@ import android.app.AppOpsManager; import android.app.BackgroundStartPrivileges; import android.app.BroadcastOptions; import android.app.IApplicationThread; import android.app.UidObserver; import android.app.usage.UsageEvents.Event; import android.app.usage.UsageStatsManagerInternal; import android.content.ComponentName; Loading Loading @@ -83,6 +84,7 @@ import android.util.proto.ProtoOutputStream; import androidx.test.filters.MediumTest; import androidx.test.platform.app.InstrumentationRegistry; import com.android.server.AlarmManagerInternal; import com.android.server.DropBoxManagerInternal; import com.android.server.LocalServices; import com.android.server.am.ActivityManagerService.Injector; Loading Loading @@ -153,11 +155,14 @@ public class BroadcastQueueTest { private PackageManagerInternal mPackageManagerInt; @Mock private UsageStatsManagerInternal mUsageStatsManagerInt; @Mock private AlarmManagerInternal mAlarmManagerInt; private ActivityManagerService mAms; private BroadcastQueue mQueue; BroadcastConstants mConstants; private BroadcastSkipPolicy mSkipPolicy; private UidObserver mUidObserver; /** * Desired behavior of the next Loading Loading @@ -204,6 +209,8 @@ public class BroadcastQueueTest { LocalServices.addService(DropBoxManagerInternal.class, mDropBoxManagerInt); LocalServices.removeServiceForTest(PackageManagerInternal.class); LocalServices.addService(PackageManagerInternal.class, mPackageManagerInt); LocalServices.removeServiceForTest(AlarmManagerInternal.class); LocalServices.addService(AlarmManagerInternal.class, mAlarmManagerInt); doReturn(new ComponentName("", "")).when(mPackageManagerInt).getSystemUiServiceComponent(); doNothing().when(mPackageManagerInt).setPackageStoppedState(any(), anyBoolean(), anyInt()); doAnswer((invocation) -> { Loading Loading @@ -281,6 +288,11 @@ public class BroadcastQueueTest { }).when(mAms).getProcessRecordLocked(any(), anyInt()); doNothing().when(mAms).appNotResponding(any(), any()); doAnswer((invocation) -> { mUidObserver = invocation.getArgument(0); return null; }).when(mAms).registerUidObserver(any(), anyInt(), anyInt(), any()); mConstants = new BroadcastConstants(Settings.Global.BROADCAST_FG_CONSTANTS); mConstants.TIMEOUT = 100; mConstants.ALLOW_BG_ACTIVITY_START_TIMEOUT = 0; Loading @@ -305,6 +317,8 @@ public class BroadcastQueueTest { } else { throw new UnsupportedOperationException(); } mQueue.start(mContext.getContentResolver()); } @After Loading Loading @@ -683,12 +697,22 @@ public class BroadcastQueueTest { anyInt(), anyInt(), any()); } private void verifyScheduleRegisteredReceiver(ProcessRecord app, private void verifyScheduleRegisteredReceiver(ProcessRecord app, Intent intent) throws Exception { verifyScheduleRegisteredReceiver(times(1), app, intent, UserHandle.USER_SYSTEM); } private void verifyScheduleRegisteredReceiver(VerificationMode mode, ProcessRecord app, Intent intent) throws Exception { verify(app.getThread()).scheduleRegisteredReceiver( verifyScheduleRegisteredReceiver(mode, app, intent, UserHandle.USER_SYSTEM); } private void verifyScheduleRegisteredReceiver(VerificationMode mode, ProcessRecord app, Intent intent, int userId) throws Exception { verify(app.getThread(), mode).scheduleRegisteredReceiver( any(), argThat(filterEqualsIgnoringComponent(intent)), anyInt(), any(), any(), anyBoolean(), anyBoolean(), anyBoolean(), eq(UserHandle.USER_SYSTEM), anyInt(), anyInt(), any()); eq(userId), anyInt(), anyInt(), any()); } private void verifyScheduleRegisteredReceiver(VerificationMode mode, ProcessRecord app, Loading Loading @@ -1934,4 +1958,49 @@ public class BroadcastQueueTest { getUidForPackage(PACKAGE_ORANGE)); assertNull(receiverOrangeApp); } /** * Verify broadcasts to runtime receivers in cached processes are deferred * until that process leaves the cached state. */ @Test public void testDeferralPolicy_UntilActive() 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); receiverGreenApp.setCached(true); receiverBlueApp.setCached(true); receiverYellowApp.setCached(false); final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED); final BroadcastOptions opts = BroadcastOptions.makeBasic() .setDeferralPolicy(BroadcastOptions.DEFERRAL_POLICY_UNTIL_ACTIVE); enqueueBroadcast(makeBroadcastRecord(airplane, callerApp, opts, List.of(makeRegisteredReceiver(receiverGreenApp), makeRegisteredReceiver(receiverBlueApp), makeManifestReceiver(PACKAGE_BLUE, CLASS_BLUE), makeRegisteredReceiver(receiverYellowApp)))); waitForIdle(); // Green ignored since it's in cached state verifyScheduleRegisteredReceiver(never(), receiverGreenApp, airplane); // Blue delivered both since it has a manifest receiver verifyScheduleReceiver(times(1), receiverBlueApp, airplane); verifyScheduleRegisteredReceiver(times(1), receiverBlueApp, airplane); // Yellow delivered since it's not cached verifyScheduleRegisteredReceiver(times(1), receiverYellowApp, airplane); // Shift green to be active and confirm that deferred broadcast is delivered receiverGreenApp.setCached(false); mUidObserver.onUidCachedChanged(getUidForPackage(PACKAGE_GREEN), false); waitForIdle(); verifyScheduleRegisteredReceiver(times(1), receiverGreenApp, airplane); } }