diff options
| author | 2024-09-03 07:06:19 +0000 | |
|---|---|---|
| committer | 2024-09-03 07:06:19 +0000 | |
| commit | c53e36a6757852197e600c97070cfabc18615770 (patch) | |
| tree | ce416404780f2f09bdff63efb849b52b4001e0db | |
| parent | 3131d5db97cc635f2c2dfabeb5017b888ae9d56d (diff) | |
| parent | 35fe27825cb36ad48a19bf174f68f4ff5e5b9e55 (diff) | |
Merge changes I36f5f7cd,Idb69119a,I5740fea0 into main
* changes:
Implement ALLOW_IF_VISIBLE opt-in
Split checks for visibility and other exemptions
Introduce BAL Configuration object
6 files changed, 279 insertions, 74 deletions
diff --git a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java index a5cea34bf79d..2259b5a5b08c 100644 --- a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java +++ b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java @@ -21,10 +21,10 @@ import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT; 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; +import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_IF_VISIBLE; import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_COMPAT; import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_DENIED; import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED; -import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_IF_VISIBLE; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE; @@ -39,13 +39,15 @@ import static com.android.server.wm.ActivityStarter.ASM_RESTRICTIONS; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ACTIVITY_STARTS; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; +import static com.android.server.wm.ActivityTaskManagerService.ACTIVITY_BG_START_GRACE_PERIOD_MS; 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.balImprovedMetrics; import static com.android.window.flags.Flags.balImproveRealCallerVisibilityCheck; +import static com.android.window.flags.Flags.balImprovedMetrics; import static com.android.window.flags.Flags.balRequireOptInByPendingIntentCreator; import static com.android.window.flags.Flags.balRequireOptInSameUid; import static com.android.window.flags.Flags.balRespectAppSwitchStateWhenCheckBoundByForegroundUid; @@ -84,6 +86,7 @@ import com.android.internal.util.FrameworkStatsLog; import com.android.internal.util.Preconditions; import com.android.server.UiThread; import com.android.server.am.PendingIntentRecord; +import com.android.server.wm.BackgroundLaunchProcessController.BalCheckConfiguration; import java.lang.annotation.Retention; import java.util.ArrayList; @@ -107,6 +110,17 @@ public class BackgroundActivityStartController { private static final int ASM_GRACEPERIOD_MAX_REPEATS = 5; private static final int NO_PROCESS_UID = -1; + private static final BalCheckConfiguration BAL_CHECK_FOREGROUND = new BalCheckConfiguration( + /* isCheckingForFgsStarts */ false, + /* checkVisibility */ true, + /* checkOtherExemptions */ false, + ACTIVITY_BG_START_GRACE_PERIOD_MS); + private static final BalCheckConfiguration BAL_CHECK_BACKGROUND = new BalCheckConfiguration( + /* isCheckingForFgsStarts */ false, + /* checkVisibility */ false, + /* checkOtherExemptions */ true, + ACTIVITY_BG_START_GRACE_PERIOD_MS); + static final String AUTO_OPT_IN_NOT_PENDING_INTENT = "notPendingIntent"; static final String AUTO_OPT_IN_CALL_FOR_RESULT = "callForResult"; static final String AUTO_OPT_IN_SAME_UID = "sameUid"; @@ -412,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; @@ -752,7 +768,7 @@ public class BackgroundActivityStartController { // PendingIntents is null). BalVerdict resultForRealCaller = state.callerIsRealCaller() && resultForCaller.allows() ? resultForCaller - : checkBackgroundActivityStartAllowedBySender(state) + : checkBackgroundActivityStartAllowedByRealCaller(state) .setBasedOnRealCaller(); state.setResultForRealCaller(resultForRealCaller); @@ -827,6 +843,37 @@ public class BackgroundActivityStartController { * or {@link #BAL_BLOCK} if the launch should be blocked */ BalVerdict checkBackgroundActivityStartAllowedByCaller(BalState 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 A code denoting which BAL rule allows an activity to be started, + * or {@link #BAL_BLOCK} if the launch should be blocked + */ + BalVerdict checkBackgroundActivityStartAllowedByCallerInForeground(BalState state) { // This is used to block background activity launch even if the app is still // visible to user after user clicking home button. @@ -842,7 +889,16 @@ public class BackgroundActivityStartController { return new BalVerdict(BAL_ALLOW_NON_APP_VISIBLE_WINDOW, /*background*/ false, "callingUid has non-app visible window"); } + // Don't abort if the callerApp or other processes of that uid are considered to be in the + // foreground. + return checkProcessAllowsBal(state.mCallerApp, state, BAL_CHECK_FOREGROUND); + } + /** + * @return A code denoting which BAL rule allows an activity to be started, + * or {@link #BAL_BLOCK} if the launch should be blocked + */ + BalVerdict checkBackgroundActivityStartAllowedByCallerInBackground(BalState state) { // don't abort for the most important UIDs final int callingAppId = UserHandle.getAppId(state.mCallingUid); if (state.mCallingUid == Process.ROOT_UID @@ -922,25 +978,29 @@ public class BackgroundActivityStartController { "OP_SYSTEM_EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION appop is granted"); } - // If we don't have callerApp at this point, no caller was provided to startActivity(). - // That's the case for PendingIntent-based starts, since the creator's process might not be - // up and alive. // Don't abort if the callerApp or other processes of that uid are allowed in any way. - BalVerdict callerAppAllowsBal = checkProcessAllowsBal(state.mCallerApp, state); - if (callerAppAllowsBal.allows()) { - return callerAppAllowsBal; - } - - // If we are here, it means all exemptions based on the creator failed - return BalVerdict.BLOCK; + return checkProcessAllowsBal(state.mCallerApp, state, BAL_CHECK_BACKGROUND); } /** * @return A code denoting which BAL rule allows an activity to be started, * or {@link #BAL_BLOCK} if the launch should be blocked */ - BalVerdict checkBackgroundActivityStartAllowedBySender(BalState state) { + BalVerdict checkBackgroundActivityStartAllowedByRealCaller(BalState state) { + BalVerdict result = checkBackgroundActivityStartAllowedByRealCallerInForeground(state); + if (result == BalVerdict.BLOCK && !(balAdditionalStartModes() + && state.mCheckedOptions.getPendingIntentBackgroundActivityStartMode() + == MODE_BACKGROUND_ACTIVITY_START_ALLOW_IF_VISIBLE)) { + result = checkBackgroundActivityStartAllowedByRealCallerInBackground(state); + } + return result; + } + /** + * @return A code denoting which BAL rule allows an activity to be started, + * or {@link #BAL_BLOCK} if the launch should be blocked + */ + BalVerdict checkBackgroundActivityStartAllowedByRealCallerInForeground(BalState state) { // Normal apps with visible app window will be allowed to start activity if app switching // is allowed, or apps like live wallpaper with non app visible window will be allowed. // The home app can start apps even if app switches are usually disallowed. @@ -966,6 +1026,16 @@ public class BackgroundActivityStartController { } } + // Don't abort if the realCallerApp or other processes of that uid are considered to be in + // the foreground. + return checkProcessAllowsBal(state.mRealCallerApp, state, BAL_CHECK_FOREGROUND); + } + + /** + * @return A code denoting which BAL rule allows an activity to be started, + * or {@link #BAL_BLOCK} if the launch should be blocked + */ + BalVerdict checkBackgroundActivityStartAllowedByRealCallerInBackground(BalState state) { if (state.mCheckedOptions.getPendingIntentBackgroundActivityStartMode() == MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS && hasBalPermission(state.mRealCallingUid, state.mRealCallingPid)) { @@ -992,14 +1062,7 @@ public class BackgroundActivityStartController { } // don't abort if the callerApp or other processes of that uid are allowed in any way - BalVerdict realCallerAppAllowsBal = - checkProcessAllowsBal(state.mRealCallerApp, state); - if (realCallerAppAllowsBal.allows()) { - return realCallerAppAllowsBal; - } - - // If we are here, it means all exemptions based on PI sender failed - return BalVerdict.BLOCK; + return checkProcessAllowsBal(state.mRealCallerApp, state, BAL_CHECK_BACKGROUND); } @VisibleForTesting boolean hasBalPermission(int uid, int pid) { @@ -1015,13 +1078,13 @@ public class BackgroundActivityStartController { * exceptions. */ @VisibleForTesting BalVerdict checkProcessAllowsBal(WindowProcessController app, - BalState state) { + BalState state, BalCheckConfiguration balCheckConfiguration) { if (app == null) { return BalVerdict.BLOCK; } // first check the original calling process final BalVerdict balAllowedForCaller = app - .areBackgroundActivityStartsAllowed(state.mAppSwitchState); + .areBackgroundActivityStartsAllowed(state.mAppSwitchState, balCheckConfiguration); if (balAllowedForCaller.allows()) { return balAllowedForCaller.withProcessInfo("callerApp process", app); } else { @@ -1033,7 +1096,7 @@ public class BackgroundActivityStartController { final WindowProcessController proc = uidProcesses.valueAt(i); if (proc != app) { BalVerdict balAllowedForUid = proc.areBackgroundActivityStartsAllowed( - state.mAppSwitchState); + state.mAppSwitchState, balCheckConfiguration); if (balAllowedForUid.allows()) { return balAllowedForUid.withProcessInfo("process", proc); } diff --git a/services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java b/services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java index 5f5365dca1e9..1073713cca52 100644 --- a/services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java +++ b/services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java @@ -98,42 +98,63 @@ class BackgroundLaunchProcessController { mBackgroundActivityStartCallback = callback; } + record BalCheckConfiguration( + boolean isCheckingForFgsStart, + boolean checkVisibility, + boolean checkOtherExemptions, + long gracePeriod + ) { + } + + /** + * Check configuration for foreground service starts. + * + * The check executes all parts of the BAL checks and uses the same grace period, + * so FGS is allowed whenever BAL is allowed. + */ + static final BalCheckConfiguration CHECK_FOR_FGS_START = new BalCheckConfiguration( + /* isCheckingForFgsStarts */ true, + /* checkVisibility */ true, + /* checkOtherExemptions */ true, + ACTIVITY_BG_START_GRACE_PERIOD_MS); + BalVerdict areBackgroundActivityStartsAllowed( int pid, int uid, String packageName, - int appSwitchState, boolean isCheckingForFgsStart, + int appSwitchState, BalCheckConfiguration checkConfiguration, boolean hasActivityInVisibleTask, boolean hasBackgroundActivityStartPrivileges, long lastStopAppSwitchesTime, long lastActivityLaunchTime, long lastActivityFinishTime) { // Allow if the proc is instrumenting with background activity starts privs. - if (hasBackgroundActivityStartPrivileges) { + if (checkConfiguration.checkOtherExemptions && hasBackgroundActivityStartPrivileges) { return new BalVerdict(BAL_ALLOW_PERMISSION, /*background*/ true, "process instrumenting with background activity starts privileges"); } // Allow if the flag was explicitly set. - if (isBackgroundStartAllowedByToken(uid, packageName, isCheckingForFgsStart)) { + if (checkConfiguration.checkOtherExemptions && isBackgroundStartAllowedByToken(uid, + packageName, checkConfiguration.isCheckingForFgsStart)) { return new BalVerdict(balImprovedMetrics() ? BAL_ALLOW_TOKEN : BAL_ALLOW_PERMISSION, /*background*/ true, "process allowed by token"); } // Allow if the caller is bound by a UID that's currently foreground. // But still respect the appSwitchState. - boolean allowBoundByForegroundUid = + if (checkConfiguration.checkVisibility && ( Flags.balRespectAppSwitchStateWhenCheckBoundByForegroundUid() - ? appSwitchState != APP_SWITCH_DISALLOW && isBoundByForegroundUid() - : isBoundByForegroundUid(); - if (allowBoundByForegroundUid) { + ? appSwitchState != APP_SWITCH_DISALLOW && isBoundByForegroundUid() + : isBoundByForegroundUid())) { return new BalVerdict(balImprovedMetrics() ? BAL_ALLOW_BOUND_BY_FOREGROUND : BAL_ALLOW_VISIBLE_WINDOW, /*background*/ false, "process bound by foreground uid"); } // Allow if the caller has an activity in any foreground task. - if (hasActivityInVisibleTask && appSwitchState != APP_SWITCH_DISALLOW) { + if (checkConfiguration.checkVisibility && hasActivityInVisibleTask + && appSwitchState != APP_SWITCH_DISALLOW) { return new BalVerdict(BAL_ALLOW_FOREGROUND, /*background*/ false, "process has activity in foreground task"); } // If app switching is not allowed, we ignore all the start activity grace period // exception so apps cannot start itself in onPause() after pressing home button. - if (appSwitchState == APP_SWITCH_ALLOW) { + if (checkConfiguration.checkOtherExemptions && appSwitchState == APP_SWITCH_ALLOW) { // Allow if any activity in the caller has either started or finished very recently, and // it must be started or finished after last stop app switches time. if (lastActivityLaunchTime > lastStopAppSwitchesTime @@ -141,9 +162,9 @@ class BackgroundLaunchProcessController { final long now = SystemClock.uptimeMillis(); long timeSinceLastStartOrFinish = now - Math.max(lastActivityLaunchTime, lastActivityFinishTime); - if (timeSinceLastStartOrFinish < ACTIVITY_BG_START_GRACE_PERIOD_MS) { + if (timeSinceLastStartOrFinish < checkConfiguration.gracePeriod) { return new BalVerdict(BAL_ALLOW_GRACE_PERIOD, /*background*/ true, - "within " + ACTIVITY_BG_START_GRACE_PERIOD_MS + "ms grace period (" + "within " + checkConfiguration.gracePeriod + "ms grace period (" + timeSinceLastStartOrFinish + "ms)"); } } diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java index d96ebc6655ac..b6b36c716a53 100644 --- a/services/core/java/com/android/server/wm/WindowProcessController.java +++ b/services/core/java/com/android/server/wm/WindowProcessController.java @@ -89,6 +89,7 @@ import com.android.internal.util.function.pooled.PooledLambda; import com.android.server.Watchdog; import com.android.server.grammaticalinflection.GrammaticalInflectionManagerInternal; import com.android.server.wm.ActivityTaskManagerService.HotPath; +import com.android.server.wm.BackgroundLaunchProcessController.BalCheckConfiguration; import java.io.IOException; import java.io.PrintWriter; @@ -695,20 +696,13 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio public boolean areBackgroundFgsStartsAllowed() { return areBackgroundActivityStartsAllowed( mAtm.getBalAppSwitchesState(), - true /* isCheckingForFgsStart */).allows(); + BackgroundLaunchProcessController.CHECK_FOR_FGS_START).allows(); } BackgroundActivityStartController.BalVerdict areBackgroundActivityStartsAllowed( - int appSwitchState) { - return areBackgroundActivityStartsAllowed( - appSwitchState, - false /* isCheckingForFgsStart */); - } - - private BackgroundActivityStartController.BalVerdict areBackgroundActivityStartsAllowed( - int appSwitchState, boolean isCheckingForFgsStart) { + int appSwitchState, BalCheckConfiguration checkConfiguration) { return mBgLaunchController.areBackgroundActivityStartsAllowed(mPid, mUid, - mInfo.packageName, appSwitchState, isCheckingForFgsStart, + mInfo.packageName, appSwitchState, checkConfiguration, hasActivityInVisibleTask(), mInstrumentingWithBackgroundActivityStartPrivileges, mAtm.getLastStopAppSwitchesTime(), mLastActivityLaunchTime, mLastActivityFinishTime); 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 6e488188eb87..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,9 +26,11 @@ 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; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; @@ -43,6 +46,9 @@ 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; import android.util.Pair; @@ -52,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; @@ -95,7 +102,9 @@ public class BackgroundActivityStartControllerExemptionTests { @Rule public final ExtendedMockitoRule extendedMockitoRule = new ExtendedMockitoRule.Builder(this).setStrictness(Strictness.LENIENT).build(); - + @Rule + public final CheckFlagsRule mCheckFlagsRule = + DeviceFlagsValueProvider.createCheckFlagsRule(); TestableBackgroundActivityStartController mController; @Mock ActivityMetricsLogger mActivityMetricsLogger; @@ -186,7 +195,7 @@ public class BackgroundActivityStartControllerExemptionTests { when(mAppOpsManager.checkOpNoThrow( eq(AppOpsManager.OP_SYSTEM_EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION), anyInt(), anyString())).thenReturn(AppOpsManager.MODE_DEFAULT); - when(mCallerApp.areBackgroundActivityStartsAllowed(anyInt())).thenReturn( + when(mCallerApp.areBackgroundActivityStartsAllowed(anyInt(), any())).thenReturn( BalVerdict.BLOCK); } @@ -227,7 +236,7 @@ public class BackgroundActivityStartControllerExemptionTests { // call BalVerdict callerVerdict = mController.checkBackgroundActivityStartAllowedByCaller( balState); - BalVerdict realCallerVerdict = mController.checkBackgroundActivityStartAllowedBySender( + BalVerdict realCallerVerdict = mController.checkBackgroundActivityStartAllowedByRealCaller( balState); balState.setResultForCaller(callerVerdict); @@ -295,7 +304,77 @@ public class BackgroundActivityStartControllerExemptionTests { checkedOptions); // call - BalVerdict realCallerVerdict = mController.checkBackgroundActivityStartAllowedBySender( + BalVerdict realCallerVerdict = mController.checkBackgroundActivityStartAllowedByRealCaller( + balState); + balState.setResultForRealCaller(realCallerVerdict); + + // assertions + assertWithMessage(balState.toString()).that(realCallerVerdict.getCode()).isEqualTo( + BAL_ALLOW_VISIBLE_WINDOW); + } + + @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); @@ -320,7 +399,7 @@ public class BackgroundActivityStartControllerExemptionTests { int realCallingPid = REGULAR_PID_2; // setup state - when(mCallerApp.areBackgroundActivityStartsAllowed(anyInt())).thenReturn( + when(mCallerApp.areBackgroundActivityStartsAllowed(anyInt(), any())).thenReturn( new BalVerdict(BAL_ALLOW_FOREGROUND, false, "allowed")); when(mService.getBalAppSwitchesState()).thenReturn(APP_SWITCH_ALLOW); @@ -357,7 +436,7 @@ public class BackgroundActivityStartControllerExemptionTests { mService.getProcessController(eq(realCallingPid), eq(realCallingUid))).thenReturn( mCallerApp); when(mService.getBalAppSwitchesState()).thenReturn(APP_SWITCH_ALLOW); - when(mCallerApp.areBackgroundActivityStartsAllowed(anyInt())).thenReturn( + when(mCallerApp.areBackgroundActivityStartsAllowed(anyInt(), any())).thenReturn( new BalVerdict(BAL_ALLOW_FOREGROUND, false, "allowed")); // prepare call @@ -371,7 +450,7 @@ public class BackgroundActivityStartControllerExemptionTests { checkedOptions); // call - BalVerdict realCallerVerdict = mController.checkBackgroundActivityStartAllowedBySender( + BalVerdict realCallerVerdict = mController.checkBackgroundActivityStartAllowedByRealCaller( balState); balState.setResultForRealCaller(realCallerVerdict); @@ -404,9 +483,9 @@ public class BackgroundActivityStartControllerExemptionTests { mService.getProcessController(eq(realCallingPid), eq(realCallingUid))).thenReturn( mCallerApp); when(mService.getBalAppSwitchesState()).thenReturn(APP_SWITCH_ALLOW); - when(mCallerApp.areBackgroundActivityStartsAllowed(anyInt())).thenReturn( + when(mCallerApp.areBackgroundActivityStartsAllowed(anyInt(), any())).thenReturn( BalVerdict.BLOCK); - when(otherProcess.areBackgroundActivityStartsAllowed(anyInt())).thenReturn( + when(otherProcess.areBackgroundActivityStartsAllowed(anyInt(), any())).thenReturn( new BalVerdict(BAL_ALLOW_FOREGROUND, false, "allowed")); // prepare call @@ -420,7 +499,7 @@ public class BackgroundActivityStartControllerExemptionTests { checkedOptions); // call - BalVerdict realCallerVerdict = mController.checkBackgroundActivityStartAllowedBySender( + BalVerdict realCallerVerdict = mController.checkBackgroundActivityStartAllowedByRealCaller( balState); balState.setResultForRealCaller(realCallerVerdict); @@ -456,7 +535,7 @@ public class BackgroundActivityStartControllerExemptionTests { checkedOptions); // call - BalVerdict realCallerVerdict = mController.checkBackgroundActivityStartAllowedBySender( + BalVerdict realCallerVerdict = mController.checkBackgroundActivityStartAllowedByRealCaller( balState); balState.setResultForRealCaller(realCallerVerdict); @@ -466,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; @@ -523,7 +641,7 @@ public class BackgroundActivityStartControllerExemptionTests { checkedOptions); // call - BalVerdict realCallerVerdict = mController.checkBackgroundActivityStartAllowedBySender( + BalVerdict realCallerVerdict = mController.checkBackgroundActivityStartAllowedByRealCaller( balState); balState.setResultForRealCaller(realCallerVerdict); diff --git a/services/tests/wmtests/src/com/android/server/wm/BackgroundActivityStartControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/BackgroundActivityStartControllerTests.java index e364264fc74f..6ec789599482 100644 --- a/services/tests/wmtests/src/com/android/server/wm/BackgroundActivityStartControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/BackgroundActivityStartControllerTests.java @@ -24,6 +24,7 @@ import static com.android.window.flags.Flags.balImprovedMetrics; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; @@ -43,6 +44,7 @@ import androidx.test.filters.SmallTest; import com.android.compatibility.common.util.DeviceConfigStateHelper; import com.android.server.am.PendingIntentRecord; import com.android.server.wm.BackgroundActivityStartController.BalVerdict; +import com.android.server.wm.BackgroundLaunchProcessController.BalCheckConfiguration; import org.junit.After; import org.junit.Before; @@ -167,9 +169,9 @@ public class BackgroundActivityStartControllerTests { } @Override - BalVerdict checkBackgroundActivityStartAllowedBySender(BalState state) { + BalVerdict checkBackgroundActivityStartAllowedByRealCaller(BalState state) { return mRealCallerVerdict.orElseGet( - () -> super.checkBackgroundActivityStartAllowedBySender(state)); + () -> super.checkBackgroundActivityStartAllowedByRealCaller(state)); } public void setRealCallerVerdict(BalVerdict verdict) { @@ -177,11 +179,12 @@ public class BackgroundActivityStartControllerTests { } @Override - BalVerdict checkProcessAllowsBal(WindowProcessController app, BalState state) { + BalVerdict checkProcessAllowsBal(WindowProcessController app, BalState state, + BalCheckConfiguration checkConfiguration) { if (mProcessVerdicts.containsKey(app)) { return mProcessVerdicts.get(app); } - return super.checkProcessAllowsBal(app, state); + return super.checkProcessAllowsBal(app, state, checkConfiguration); } } @@ -209,7 +212,7 @@ public class BackgroundActivityStartControllerTests { Mockito.when(mAppOpsManager.checkOpNoThrow( eq(AppOpsManager.OP_SYSTEM_EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION), anyInt(), anyString())).thenReturn(AppOpsManager.MODE_DEFAULT); - Mockito.when(mCallerApp.areBackgroundActivityStartsAllowed(anyInt())).thenReturn( + Mockito.when(mCallerApp.areBackgroundActivityStartsAllowed(anyInt(), any())).thenReturn( BalVerdict.BLOCK); } diff --git a/services/tests/wmtests/src/com/android/server/wm/BackgroundLaunchProcessControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/BackgroundLaunchProcessControllerTests.java index c9c7e92d71cd..27e147d98b1f 100644 --- a/services/tests/wmtests/src/com/android/server/wm/BackgroundLaunchProcessControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/BackgroundLaunchProcessControllerTests.java @@ -16,6 +16,7 @@ package com.android.server.wm; +import static com.android.server.wm.ActivityTaskManagerService.ACTIVITY_BG_START_GRACE_PERIOD_MS; import static com.android.server.wm.ActivityTaskManagerService.APP_SWITCH_ALLOW; import static com.android.server.wm.ActivityTaskManagerService.APP_SWITCH_DISALLOW; import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_BOUND_BY_FOREGROUND; @@ -95,7 +96,12 @@ public class BackgroundLaunchProcessControllerTests { int mUid = 234; String mPackageName = "package.name"; int mAppSwitchState = APP_SWITCH_DISALLOW; - boolean mIsCheckingForFgsStart = false; + BackgroundLaunchProcessController.BalCheckConfiguration mBalCheckConfiguration = + new BackgroundLaunchProcessController.BalCheckConfiguration( + /* isCheckingForFgsStarts */ false, + /* checkVisibility */ true, + /* checkOtherExemptions */ true, + ACTIVITY_BG_START_GRACE_PERIOD_MS); boolean mHasActivityInVisibleTask = false; boolean mHasBackgroundActivityStartPrivileges = false; long mLastStopAppSwitchesTime = 0L; @@ -106,7 +112,7 @@ public class BackgroundLaunchProcessControllerTests { public void testNothingAllows() { BalVerdict balVerdict = mController.areBackgroundActivityStartsAllowed( mPid, mUid, mPackageName, - mAppSwitchState, mIsCheckingForFgsStart, + mAppSwitchState, mBalCheckConfiguration, mHasActivityInVisibleTask, mHasBackgroundActivityStartPrivileges, mLastStopAppSwitchesTime, mLastActivityLaunchTime, mLastActivityFinishTime); @@ -118,7 +124,7 @@ public class BackgroundLaunchProcessControllerTests { mHasBackgroundActivityStartPrivileges = true; BalVerdict balVerdict = mController.areBackgroundActivityStartsAllowed( mPid, mUid, mPackageName, - mAppSwitchState, mIsCheckingForFgsStart, + mAppSwitchState, mBalCheckConfiguration, mHasActivityInVisibleTask, mHasBackgroundActivityStartPrivileges, mLastStopAppSwitchesTime, mLastActivityLaunchTime, mLastActivityFinishTime); @@ -136,7 +142,7 @@ public class BackgroundLaunchProcessControllerTests { BackgroundStartPrivileges.ALLOW_BAL); BalVerdict balVerdict = mController.areBackgroundActivityStartsAllowed( mPid, mUid, mPackageName, - mAppSwitchState, mIsCheckingForFgsStart, + mAppSwitchState, mBalCheckConfiguration, mHasActivityInVisibleTask, mHasBackgroundActivityStartPrivileges, mLastStopAppSwitchesTime, mLastActivityLaunchTime, mLastActivityFinishTime); @@ -154,7 +160,7 @@ public class BackgroundLaunchProcessControllerTests { BackgroundStartPrivileges.ALLOW_BAL); BalVerdict balVerdict = mController.areBackgroundActivityStartsAllowed( mPid, mUid, mPackageName, - mAppSwitchState, mIsCheckingForFgsStart, + mAppSwitchState, mBalCheckConfiguration, mHasActivityInVisibleTask, mHasBackgroundActivityStartPrivileges, mLastStopAppSwitchesTime, mLastActivityLaunchTime, mLastActivityFinishTime); @@ -170,7 +176,7 @@ public class BackgroundLaunchProcessControllerTests { BackgroundStartPrivileges.ALLOW_BAL); BalVerdict balVerdict = mController.areBackgroundActivityStartsAllowed( mPid, mUid, mPackageName, - mAppSwitchState, mIsCheckingForFgsStart, + mAppSwitchState, mBalCheckConfiguration, mHasActivityInVisibleTask, mHasBackgroundActivityStartPrivileges, mLastStopAppSwitchesTime, mLastActivityLaunchTime, mLastActivityFinishTime); @@ -186,7 +192,7 @@ public class BackgroundLaunchProcessControllerTests { BackgroundStartPrivileges.ALLOW_BAL); BalVerdict balVerdict = mController.areBackgroundActivityStartsAllowed( mPid, mUid, mPackageName, - mAppSwitchState, mIsCheckingForFgsStart, + mAppSwitchState, mBalCheckConfiguration, mHasActivityInVisibleTask, mHasBackgroundActivityStartPrivileges, mLastStopAppSwitchesTime, mLastActivityLaunchTime, mLastActivityFinishTime); @@ -201,7 +207,7 @@ public class BackgroundLaunchProcessControllerTests { mHasActiveVisibleWindow.add(999); BalVerdict balVerdict = mController.areBackgroundActivityStartsAllowed( mPid, mUid, mPackageName, - mAppSwitchState, mIsCheckingForFgsStart, + mAppSwitchState, mBalCheckConfiguration, mHasActivityInVisibleTask, mHasBackgroundActivityStartPrivileges, mLastStopAppSwitchesTime, mLastActivityLaunchTime, mLastActivityFinishTime); @@ -216,7 +222,7 @@ public class BackgroundLaunchProcessControllerTests { mHasActiveVisibleWindow.add(999); BalVerdict balVerdict = mController.areBackgroundActivityStartsAllowed( mPid, mUid, mPackageName, - mAppSwitchState, mIsCheckingForFgsStart, + mAppSwitchState, mBalCheckConfiguration, mHasActivityInVisibleTask, mHasBackgroundActivityStartPrivileges, mLastStopAppSwitchesTime, mLastActivityLaunchTime, mLastActivityFinishTime); @@ -229,7 +235,7 @@ public class BackgroundLaunchProcessControllerTests { mHasActivityInVisibleTask = true; BalVerdict balVerdict = mController.areBackgroundActivityStartsAllowed( mPid, mUid, mPackageName, - mAppSwitchState, mIsCheckingForFgsStart, + mAppSwitchState, mBalCheckConfiguration, mHasActivityInVisibleTask, mHasBackgroundActivityStartPrivileges, mLastStopAppSwitchesTime, mLastActivityLaunchTime, mLastActivityFinishTime); @@ -245,7 +251,7 @@ public class BackgroundLaunchProcessControllerTests { mLastActivityFinishTime = now - 100; BalVerdict balVerdict = mController.areBackgroundActivityStartsAllowed( mPid, mUid, mPackageName, - mAppSwitchState, mIsCheckingForFgsStart, + mAppSwitchState, mBalCheckConfiguration, mHasActivityInVisibleTask, mHasBackgroundActivityStartPrivileges, mLastStopAppSwitchesTime, mLastActivityLaunchTime, mLastActivityFinishTime); |