diff options
2 files changed, 142 insertions, 5 deletions
diff --git a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java index 7d846e59b69f..2259b5a5b08c 100644 --- a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java +++ b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java @@ -44,6 +44,7 @@ import static com.android.server.wm.ActivityTaskManagerService.APP_SWITCH_ALLOW; import static com.android.server.wm.ActivityTaskManagerService.APP_SWITCH_FG_ONLY; import static com.android.server.wm.ActivityTaskSupervisor.getApplicationLabel; import static com.android.server.wm.PendingRemoteAnimationRegistry.TIMEOUT_MS; +import static com.android.window.flags.Flags.balAdditionalStartModes; import static com.android.window.flags.Flags.balDontBringExistingBackgroundTaskStackToFg; import static com.android.window.flags.Flags.balImproveRealCallerVisibilityCheck; import static com.android.window.flags.Flags.balImprovedMetrics; @@ -425,6 +426,8 @@ public class BackgroundActivityStartController { int callingUid, String callingPackage, ActivityOptions checkedOptions) { switch (checkedOptions.getPendingIntentCreatorBackgroundActivityStartMode()) { case MODE_BACKGROUND_ACTIVITY_START_ALLOWED: + case MODE_BACKGROUND_ACTIVITY_START_ALLOW_IF_VISIBLE: + case MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS: return BackgroundStartPrivileges.ALLOW_BAL; case MODE_BACKGROUND_ACTIVITY_START_DENIED: return BackgroundStartPrivileges.NONE; @@ -840,11 +843,30 @@ public class BackgroundActivityStartController { * or {@link #BAL_BLOCK} if the launch should be blocked */ BalVerdict checkBackgroundActivityStartAllowedByCaller(BalState state) { - BalVerdict result = checkBackgroundActivityStartAllowedByCallerInForeground(state); - if (result == BalVerdict.BLOCK) { - result = checkBackgroundActivityStartAllowedByCallerInBackground(state); + if (state.isPendingIntent()) { + // PendingIntents should mostly be allowed by the sender (real caller) or a permission + // the creator of the PendingIntent has. Visibility should be the exceptional case, so + // test it last (this does not change the result, just the bal code). + BalVerdict result = BalVerdict.BLOCK; + if (!(balAdditionalStartModes() + && state.mCheckedOptions.getPendingIntentCreatorBackgroundActivityStartMode() + == MODE_BACKGROUND_ACTIVITY_START_ALLOW_IF_VISIBLE)) { + result = checkBackgroundActivityStartAllowedByCallerInBackground(state); + } + if (result == BalVerdict.BLOCK) { + result = checkBackgroundActivityStartAllowedByCallerInForeground(state); + + } + return result; + } else { + BalVerdict result = checkBackgroundActivityStartAllowedByCallerInForeground(state); + if (result == BalVerdict.BLOCK && !(balAdditionalStartModes() + && state.mCheckedOptions.getPendingIntentCreatorBackgroundActivityStartMode() + == MODE_BACKGROUND_ACTIVITY_START_ALLOW_IF_VISIBLE)) { + result = checkBackgroundActivityStartAllowedByCallerInBackground(state); + } + return result; } - return result; } /** @@ -966,7 +988,9 @@ public class BackgroundActivityStartController { */ BalVerdict checkBackgroundActivityStartAllowedByRealCaller(BalState state) { BalVerdict result = checkBackgroundActivityStartAllowedByRealCallerInForeground(state); - if (result == BalVerdict.BLOCK) { + if (result == BalVerdict.BLOCK && !(balAdditionalStartModes() + && state.mCheckedOptions.getPendingIntentBackgroundActivityStartMode() + == MODE_BACKGROUND_ACTIVITY_START_ALLOW_IF_VISIBLE)) { result = checkBackgroundActivityStartAllowedByRealCallerInBackground(state); } return result; diff --git a/services/tests/wmtests/src/com/android/server/wm/BackgroundActivityStartControllerExemptionTests.java b/services/tests/wmtests/src/com/android/server/wm/BackgroundActivityStartControllerExemptionTests.java index 5246850eb6fd..3910904337b2 100644 --- a/services/tests/wmtests/src/com/android/server/wm/BackgroundActivityStartControllerExemptionTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/BackgroundActivityStartControllerExemptionTests.java @@ -18,6 +18,7 @@ package com.android.server.wm; 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 com.android.server.wm.ActivityTaskManagerService.APP_SWITCH_ALLOW; import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_ALLOWLISTED_COMPONENT; @@ -25,6 +26,7 @@ import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_ import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_PERMISSION; import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_SAW_PERMISSION; import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_VISIBLE_WINDOW; +import static com.android.server.wm.BackgroundActivityStartController.BAL_BLOCK; import static com.google.common.truth.Truth.assertWithMessage; @@ -44,6 +46,7 @@ import android.content.Intent; import android.content.pm.PackageManagerInternal; import android.os.UserHandle; import android.platform.test.annotations.Presubmit; +import android.platform.test.annotations.RequiresFlagsEnabled; import android.platform.test.flag.junit.CheckFlagsRule; import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.provider.DeviceConfig; @@ -55,6 +58,7 @@ import com.android.compatibility.common.util.DeviceConfigStateHelper; import com.android.modules.utils.testing.ExtendedMockitoRule; import com.android.server.am.PendingIntentRecord; import com.android.server.wm.BackgroundActivityStartController.BalVerdict; +import com.android.window.flags.Flags; import org.junit.After; import org.junit.Before; @@ -310,6 +314,76 @@ public class BackgroundActivityStartControllerExemptionTests { } @Test + @RequiresFlagsEnabled(Flags.FLAG_BAL_ADDITIONAL_START_MODES) + public void testCaller_appHasVisibleWindowWithIfVisibleOptIn() { + 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(mService.hasActiveVisibleWindow(eq(callingUid))).thenReturn(true); + when(mService.getBalAppSwitchesState()).thenReturn(APP_SWITCH_ALLOW); + + // prepare call + PendingIntentRecord originatingPendingIntent = mPendingIntentRecord; + BackgroundStartPrivileges forcedBalByPiSender = BackgroundStartPrivileges.NONE; + Intent intent = TEST_INTENT; + ActivityOptions checkedOptions = mCheckedOptions + .setPendingIntentCreatorBackgroundActivityStartMode( + MODE_BACKGROUND_ACTIVITY_START_ALLOW_IF_VISIBLE); + BackgroundActivityStartController.BalState balState = mController.new BalState(callingUid, + callingPid, callingPackage, realCallingUid, realCallingPid, mCallerApp, + originatingPendingIntent, forcedBalByPiSender, mResultRecord, intent, + checkedOptions); + + // call + BalVerdict callerVerdict = mController.checkBackgroundActivityStartAllowedByCaller( + balState); + balState.setResultForCaller(callerVerdict); + + // assertions + assertWithMessage(balState.toString()).that(callerVerdict.getCode()).isEqualTo( + BAL_ALLOW_VISIBLE_WINDOW); + } + + @Test + @RequiresFlagsEnabled(Flags.FLAG_BAL_ADDITIONAL_START_MODES) + public void testRealCaller_appHasVisibleWindowWithIfVisibleOptIn() { + 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(mService.hasActiveVisibleWindow(eq(realCallingUid))).thenReturn(true); + when(mService.getBalAppSwitchesState()).thenReturn(APP_SWITCH_ALLOW); + + // prepare call + PendingIntentRecord originatingPendingIntent = mPendingIntentRecord; + BackgroundStartPrivileges forcedBalByPiSender = BackgroundStartPrivileges.NONE; + Intent intent = TEST_INTENT; + ActivityOptions checkedOptions = mCheckedOptions + .setPendingIntentCreatorBackgroundActivityStartMode( + MODE_BACKGROUND_ACTIVITY_START_ALLOW_IF_VISIBLE); + BackgroundActivityStartController.BalState balState = mController.new BalState(callingUid, + callingPid, callingPackage, realCallingUid, realCallingPid, mCallerApp, + originatingPendingIntent, forcedBalByPiSender, mResultRecord, intent, + checkedOptions); + + // call + BalVerdict realCallerVerdict = mController.checkBackgroundActivityStartAllowedByRealCaller( + balState); + balState.setResultForRealCaller(realCallerVerdict); + + // assertions + assertWithMessage(balState.toString()).that(realCallerVerdict.getCode()).isEqualTo( + BAL_ALLOW_VISIBLE_WINDOW); + } + + @Test public void testCaller_appAllowedByBLPC() { // This covers the cases // - The app has an activity in the back stack of the foreground task. @@ -471,6 +545,45 @@ public class BackgroundActivityStartControllerExemptionTests { } @Test + @RequiresFlagsEnabled(Flags.FLAG_BAL_ADDITIONAL_START_MODES) + public void testRealCaller_isCompanionAppWithOptInIfVisible() { + // The app has a service that is bound by a different, visible app. The app bound to the + // service must remain visible for the app in the background to start activities + // successfully. + 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 + final int realCallingUserId = UserHandle.getUserId(realCallingUid); + when(mService.isAssociatedCompanionApp(eq(realCallingUserId), + eq(realCallingUid))).thenReturn(true); + + // prepare call + PendingIntentRecord originatingPendingIntent = mPendingIntentRecord; + BackgroundStartPrivileges forcedBalByPiSender = BackgroundStartPrivileges.NONE; + Intent intent = TEST_INTENT; + ActivityOptions checkedOptions = mCheckedOptions + .setPendingIntentBackgroundActivityStartMode( + MODE_BACKGROUND_ACTIVITY_START_ALLOW_IF_VISIBLE); + BackgroundActivityStartController.BalState balState = mController.new BalState(callingUid, + callingPid, callingPackage, realCallingUid, realCallingPid, null, + originatingPendingIntent, forcedBalByPiSender, mResultRecord, intent, + checkedOptions); + + // call + BalVerdict realCallerVerdict = mController.checkBackgroundActivityStartAllowedByRealCaller( + balState); + balState.setResultForRealCaller(realCallerVerdict); + + // assertions + assertWithMessage(balState.toString()).that(realCallerVerdict.getCode()).isEqualTo( + BAL_BLOCK); + } + + @Test public void testCaller_balPermission() { int callingUid = REGULAR_UID_1; int callingPid = REGULAR_PID_1; |