Loading services/core/java/com/android/server/wm/BackgroundActivityStartController.java +18 −5 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.server.wm; import static android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND; import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT; import static android.app.ActivityManager.PROCESS_STATE_TOP; import static android.app.ActivityOptions.BackgroundActivityStartMode; import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED; import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS; Loading Loading @@ -1096,11 +1097,11 @@ public class BackgroundActivityStartController { mCheckCallerProcessInGracePeriod); } return evaluateChain(state, basedOnRealCaller, mCheckCallerVisible, mCheckCallerNonAppVisible, mCheckCallerProcessAllowsForeground, mCheckCallerIsAllowlistedUid, mCheckCallerIsAllowlistedComponent, mCheckCallerHasBackgroundPermission, mCheckCallerHasSawPermission, mCheckCallerHasBgStartAppOp, mCheckCallerProcessAllowsBackground, mCheckCallerProcessInGracePeriod); mCheckCallerNonAppVisible, mCheckCallerNonActivityTop, mCheckCallerProcessAllowsForeground, mCheckCallerIsAllowlistedUid, mCheckCallerIsAllowlistedComponent, mCheckCallerHasBackgroundPermission, mCheckCallerHasSawPermission, mCheckCallerHasBgStartAppOp, mCheckCallerProcessAllowsBackground, mCheckCallerProcessInGracePeriod); } interface BalExemptionCheck { Loading Loading @@ -1149,6 +1150,18 @@ public class BackgroundActivityStartController { return BalVerdict.BLOCK; }; private final BalExemptionCheck mCheckCallerNonActivityTop = state -> { // Allows if the UID process state is at the top and the app is not yet hosting any // activities. This is possible if the application starts an activity within its // `Application#onCreate` method when the process started, identifying a visible activity // from that app is not possible because the application process has not yet fully attached. if (state.mCallerApp != null && !state.mCallerApp.hasActivities() && state.mCallingUidProcState == PROCESS_STATE_TOP) { return new BalVerdict(BAL_ALLOW_FOREGROUND, "callingUid is the current top"); } return BalVerdict.BLOCK; }; private BalVerdict checkNonAppVisibleWindow(int uid, boolean hasNonAppVisibleWindow) { if (hasNonAppVisibleWindow) { SparseIntArray nonAppVisibleWindowDetails = Loading services/tests/wmtests/src/com/android/server/wm/BackgroundActivityStartControllerExemptionTests.java +42 −0 Original line number Diff line number Diff line Loading @@ -16,9 +16,11 @@ package com.android.server.wm; import static android.app.ActivityManager.PROCESS_STATE_TOP; import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED; import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS; import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_IF_VISIBLE; import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED; import static com.android.server.wm.ActivityTaskManagerService.APP_SWITCH_ALLOW; import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_ALLOWLISTED_COMPONENT; Loading Loading @@ -300,6 +302,46 @@ public class BackgroundActivityStartControllerExemptionTests { .isEqualTo(BAL_BLOCK); } @Test public void testCaller_appIsTop() { int callingUid = REGULAR_UID_1; int callingPid = REGULAR_PID_1; final String callingPackage = REGULAR_PACKAGE_1; int realCallingUid = REGULAR_UID_2; int realCallingPid = REGULAR_PID_2; // setup state when(mVisibleActivityProcessTracker.hasVisibleActivity(eq(callingUid))).thenReturn(false); when(mVisibleActivityProcessTracker.hasVisibleNotPinnedActivity(eq(callingUid))) .thenReturn(false); when(mService.getBalAppSwitchesState()).thenReturn(APP_SWITCH_ALLOW); mActiveUids.onUidActive(callingUid, PROCESS_STATE_TOP); // prepare call PendingIntentRecord originatingPendingIntent = null; boolean allowBalExemptionForSystemProcess = false; Intent intent = TEST_INTENT; ActivityOptions checkedOptions = mCheckedOptions .setPendingIntentCreatorBackgroundActivityStartMode( MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED); BackgroundActivityStartController.BalState balState = mController.new BalState(callingUid, callingPid, callingPackage, realCallingUid, realCallingPid, mCallerApp, originatingPendingIntent, allowBalExemptionForSystemProcess, mResultRecord, intent, checkedOptions); assertThat(balState.toString()).contains("callingUidHasVisibleActivity: false"); assertThat(balState.toString()).contains("callingUidHasVisibleNotPinnedActivity: false"); assertThat(balState.toString()).contains("callingUidHasNonAppVisibleWindow: false"); // call BalVerdict callerVerdict = mController.checkBackgroundActivityStartAllowedByCaller( balState); balState.setResultForCaller(callerVerdict); // assertions assertWithMessage(balState.toString()).that(callerVerdict.getCode()).isEqualTo( BAL_ALLOW_FOREGROUND); } @Test public void testCaller_appHasVisiblePinnedWindow() { int callingUid = REGULAR_UID_1; Loading Loading
services/core/java/com/android/server/wm/BackgroundActivityStartController.java +18 −5 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.server.wm; import static android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND; import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT; import static android.app.ActivityManager.PROCESS_STATE_TOP; import static android.app.ActivityOptions.BackgroundActivityStartMode; import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED; import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS; Loading Loading @@ -1096,11 +1097,11 @@ public class BackgroundActivityStartController { mCheckCallerProcessInGracePeriod); } return evaluateChain(state, basedOnRealCaller, mCheckCallerVisible, mCheckCallerNonAppVisible, mCheckCallerProcessAllowsForeground, mCheckCallerIsAllowlistedUid, mCheckCallerIsAllowlistedComponent, mCheckCallerHasBackgroundPermission, mCheckCallerHasSawPermission, mCheckCallerHasBgStartAppOp, mCheckCallerProcessAllowsBackground, mCheckCallerProcessInGracePeriod); mCheckCallerNonAppVisible, mCheckCallerNonActivityTop, mCheckCallerProcessAllowsForeground, mCheckCallerIsAllowlistedUid, mCheckCallerIsAllowlistedComponent, mCheckCallerHasBackgroundPermission, mCheckCallerHasSawPermission, mCheckCallerHasBgStartAppOp, mCheckCallerProcessAllowsBackground, mCheckCallerProcessInGracePeriod); } interface BalExemptionCheck { Loading Loading @@ -1149,6 +1150,18 @@ public class BackgroundActivityStartController { return BalVerdict.BLOCK; }; private final BalExemptionCheck mCheckCallerNonActivityTop = state -> { // Allows if the UID process state is at the top and the app is not yet hosting any // activities. This is possible if the application starts an activity within its // `Application#onCreate` method when the process started, identifying a visible activity // from that app is not possible because the application process has not yet fully attached. if (state.mCallerApp != null && !state.mCallerApp.hasActivities() && state.mCallingUidProcState == PROCESS_STATE_TOP) { return new BalVerdict(BAL_ALLOW_FOREGROUND, "callingUid is the current top"); } return BalVerdict.BLOCK; }; private BalVerdict checkNonAppVisibleWindow(int uid, boolean hasNonAppVisibleWindow) { if (hasNonAppVisibleWindow) { SparseIntArray nonAppVisibleWindowDetails = Loading
services/tests/wmtests/src/com/android/server/wm/BackgroundActivityStartControllerExemptionTests.java +42 −0 Original line number Diff line number Diff line Loading @@ -16,9 +16,11 @@ package com.android.server.wm; import static android.app.ActivityManager.PROCESS_STATE_TOP; import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED; import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS; import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_IF_VISIBLE; import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED; import static com.android.server.wm.ActivityTaskManagerService.APP_SWITCH_ALLOW; import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_ALLOWLISTED_COMPONENT; Loading Loading @@ -300,6 +302,46 @@ public class BackgroundActivityStartControllerExemptionTests { .isEqualTo(BAL_BLOCK); } @Test public void testCaller_appIsTop() { int callingUid = REGULAR_UID_1; int callingPid = REGULAR_PID_1; final String callingPackage = REGULAR_PACKAGE_1; int realCallingUid = REGULAR_UID_2; int realCallingPid = REGULAR_PID_2; // setup state when(mVisibleActivityProcessTracker.hasVisibleActivity(eq(callingUid))).thenReturn(false); when(mVisibleActivityProcessTracker.hasVisibleNotPinnedActivity(eq(callingUid))) .thenReturn(false); when(mService.getBalAppSwitchesState()).thenReturn(APP_SWITCH_ALLOW); mActiveUids.onUidActive(callingUid, PROCESS_STATE_TOP); // prepare call PendingIntentRecord originatingPendingIntent = null; boolean allowBalExemptionForSystemProcess = false; Intent intent = TEST_INTENT; ActivityOptions checkedOptions = mCheckedOptions .setPendingIntentCreatorBackgroundActivityStartMode( MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED); BackgroundActivityStartController.BalState balState = mController.new BalState(callingUid, callingPid, callingPackage, realCallingUid, realCallingPid, mCallerApp, originatingPendingIntent, allowBalExemptionForSystemProcess, mResultRecord, intent, checkedOptions); assertThat(balState.toString()).contains("callingUidHasVisibleActivity: false"); assertThat(balState.toString()).contains("callingUidHasVisibleNotPinnedActivity: false"); assertThat(balState.toString()).contains("callingUidHasNonAppVisibleWindow: false"); // call BalVerdict callerVerdict = mController.checkBackgroundActivityStartAllowedByCaller( balState); balState.setResultForCaller(callerVerdict); // assertions assertWithMessage(balState.toString()).that(callerVerdict.getCode()).isEqualTo( BAL_ALLOW_FOREGROUND); } @Test public void testCaller_appHasVisiblePinnedWindow() { int callingUid = REGULAR_UID_1; Loading