diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java index 2030b301f9f7ac878b22d07f6c9df1fc9a3115df..1fd8f50b9dece40527b8f13c67a007a49805c2bc 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java @@ -16,10 +16,8 @@ package com.android.server.wm; -import static android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND; import static android.app.Activity.RESULT_CANCELED; import static android.app.ActivityManager.PROCESS_STATE_BOUND_TOP; -import static android.app.ActivityManager.PROCESS_STATE_TOP; import static android.app.ActivityManager.START_ABORTED; import static android.app.ActivityManager.START_CANCELED; import static android.app.ActivityManager.START_CLASS_NOT_FOUND; @@ -44,7 +42,6 @@ import static android.content.pm.ActivityInfo.FLAG_ALLOW_UNTRUSTED_ACTIVITY_EMBE import static android.content.pm.ActivityInfo.LAUNCH_MULTIPLE; import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE; import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK; -import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.os.Process.SYSTEM_UID; import static com.android.dx.mockito.inline.extended.ExtendedMockito.clearInvocations; @@ -52,7 +49,6 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; -import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; import static com.android.dx.mockito.inline.extended.ExtendedMockito.never; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; @@ -79,15 +75,12 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.anyObject; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.notNull; import android.app.ActivityOptions; -import android.app.ActivityOptions.BackgroundActivityStartMode; import android.app.AppOpsManager; -import android.app.BackgroundStartPrivileges; import android.app.IApplicationThread; import android.app.PictureInPictureParams; import android.content.ComponentName; @@ -101,10 +94,8 @@ import android.content.pm.SigningDetails; import android.graphics.Rect; import android.os.Binder; import android.os.IBinder; -import android.os.Process; import android.os.RemoteException; import android.platform.test.annotations.Presubmit; -import android.platform.test.annotations.RequiresFlagsDisabled; import android.provider.DeviceConfig; import android.service.voice.IVoiceInteractionSession; import android.util.Pair; @@ -116,8 +107,6 @@ import android.window.TaskFragmentOrganizerToken; import androidx.test.filters.SmallTest; import com.android.compatibility.common.util.DeviceConfigStateHelper; -import com.android.internal.util.FrameworkStatsLog; -import com.android.server.am.PendingIntentRecord; import com.android.server.pm.PackageArchiver; import com.android.server.pm.pkg.AndroidPackage; import com.android.server.wm.BackgroundActivityStartController.BalVerdict; @@ -126,11 +115,8 @@ import com.android.server.wm.utils.MockTracker; import org.junit.After; import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.MockitoSession; -import org.mockito.quality.Strictness; import java.util.ArrayList; import java.util.Arrays; @@ -726,497 +712,68 @@ public class ActivityStarterTests extends WindowTestsBase { eq(FAKE_REAL_CALLING_UID), anyInt(), anyBoolean(), eq(false)); } - /** - * This test ensures that unsupported usecases aren't aborted when background starts are - * allowed. - */ - @Test - public void testBackgroundActivityStartsAllowed_noStartsAborted() { - doReturn(true).when(mAtm).isBackgroundActivityStartsEnabled(); - runAndVerifyBackgroundActivityStartsSubtest("allowed_noStartsAborted", false, - UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP, - UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, - false, false, false, false, false, false, false, false); - } - - /** - * This test ensures that unsupported usecases are aborted when background starts are - * disallowed. - */ - @Test - public void testBackgroundActivityStartsDisallowed_unsupportedUsecaseAborted() { - doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled(); - runAndVerifyBackgroundActivityStartsSubtest( - "disallowed_unsupportedUsecase_aborted", true, - UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP, - UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, - false, false, false, false, false, false, false, false); - } - - /** - * This test ensures that unsupported usecases are aborted when background starts are - * disallowed. - */ - @Test - public void testBackgroundActivityStartsDisallowed_callingUidProcessStateTopAborted() { - doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled(); - runAndVerifyBackgroundActivityStartsSubtest( - "disallowed_callingUidProcessStateTop_aborted", true, - UNIMPORTANT_UID, false, PROCESS_STATE_TOP, - UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, - false, false, false, false, false, false, false, false); - } - - /** - * This test ensures that unsupported usecases are aborted when background starts are - * disallowed. - */ - @Test - public void testBackgroundActivityStartsDisallowed_realCallingUidProcessStateTopAborted() { - doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled(); - runAndVerifyBackgroundActivityStartsSubtest( - "disallowed_realCallingUidProcessStateTop_aborted", true, - UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP, - UNIMPORTANT_UID2, false, PROCESS_STATE_TOP, - false, false, false, false, false, false, false, false); - } - - /** - * This test ensures that unsupported usecases are aborted when background starts are - * disallowed. - */ - @Test - public void testBackgroundActivityStartsDisallowed_hasForegroundActivitiesAborted() { - doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled(); - runAndVerifyBackgroundActivityStartsSubtest( - "disallowed_hasForegroundActivities_aborted", true, - UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP, - UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, - true, false, false, false, false, false, false, false); - } /** * This test ensures that unsupported usecases are aborted when background starts are * disallowed. */ @Test - public void testBackgroundActivityStartsDisallowed_pinnedSingleInstanceAborted() { + public void testPinnedSingleInstanceAborted() { doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled(); - runAndVerifyBackgroundActivityStartsSubtest( - "disallowed_pinned_singleinstance_aborted", true, - UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP, - UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, - false, false, false, false, false, false, true, false); - } - - /** - * This test ensures that supported usecases aren't aborted when background starts are - * disallowed. Each scenarios tests one condition that makes them supported in isolation. In - * this case the calling process runs as ROOT_UID. - */ - @Test - public void testBackgroundActivityStartsDisallowed_rootUidNotAborted() { - doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled(); - runAndVerifyBackgroundActivityStartsSubtest("disallowed_rootUid_notAborted", false, - Process.ROOT_UID, false, PROCESS_STATE_BOUND_TOP, - UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, - false, false, false, false, false, false, false, false); - } - - /** - * This test ensures that supported usecases aren't aborted when background starts are - * disallowed. Each scenarios tests one condition that makes them supported in isolation. In - * this case the calling process is running as SYSTEM_UID. - */ - @Test - public void testBackgroundActivityStartsDisallowed_systemUidNotAborted() { - doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled(); - runAndVerifyBackgroundActivityStartsSubtest("disallowed_systemUid_notAborted", false, - Process.SYSTEM_UID, false, PROCESS_STATE_BOUND_TOP, - UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, - false, false, false, false, false, false, false, false); - } - - /** - * This test ensures that supported usecases aren't aborted when background starts are - * disallowed. Each scenarios tests one condition that makes them supported in isolation. In - * this case the calling process is running as NFC_UID. - */ - @Test - public void testBackgroundActivityStartsDisallowed_nfcUidNotAborted() { - doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled(); - runAndVerifyBackgroundActivityStartsSubtest("disallowed_nfcUid_notAborted", false, - Process.NFC_UID, false, PROCESS_STATE_BOUND_TOP, - UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, - false, false, false, false, false, false, false, false); - } - - /** - * This test ensures that supported usecases aren't aborted when background starts are - * disallowed. Each scenarios tests one condition that makes them supported in isolation. In - * this case the calling process has a visible window. - */ - @Test - public void testBackgroundActivityStartsDisallowed_callingUidHasVisibleWindowNotAborted() { - doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled(); - runAndVerifyBackgroundActivityStartsSubtest( - "disallowed_callingUidHasVisibleWindow_notAborted", false, - UNIMPORTANT_UID, true, PROCESS_STATE_BOUND_TOP, - UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, - false, false, false, false, false, false, false, false); - } - - /** - * The sending app has a visible window, but does not (by default) allow the pending intent to - * start the background activity. - */ - @Test - @Ignore("b/266015587") - public void testBackgroundActivityStartsDisallowed_realCallingUidHasVisibleWindowAborted() { - doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled(); - - runAndVerifyBackgroundActivityStartsSubtest( - "disallowed_realCallingUidHasVisibleWindow_abortedInU", true, - UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP, - UNIMPORTANT_UID2, true, PROCESS_STATE_BOUND_TOP, - false, false, false, false, false, false, false, false); - } - - /** - * This test ensures that supported usecases aren't aborted when background starts are - * disallowed. Each scenarios tests one condition that makes them supported in isolation. In - * this case the caller is in the recent activity list. - */ - @Test - public void testBackgroundActivityStartsDisallowed_callerIsRecentsNotAborted() { - doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled(); - runAndVerifyBackgroundActivityStartsSubtest( - "disallowed_callerIsRecents_notAborted", false, - UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP, - UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, - false, true, false, false, false, false, false, false); - } - - /** - * This test ensures that supported usecases aren't aborted when background starts are - * disallowed. Each scenarios tests one condition that makes them supported in isolation. In - * this case the caller is temporarily (10s) allowed to start. - */ - @Test - public void testBackgroundActivityStartsDisallowed_callerIsAllowedNotAborted() { - doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled(); - runAndVerifyBackgroundActivityStartsSubtest( - "disallowed_callerIsAllowed_notAborted", false, - UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP, - UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, - false, false, true, false, false, false, false, false); - } - - /** - * This test ensures that supported usecases aren't aborted when background starts are - * disallowed. Each scenarios tests one condition that makes them supported in isolation. In - * this case the caller explicitly has background activity start privilege. - */ - @Test - public void testBackgroundActivityStartsDisallowed_callerIsInstrumentingWithBASPnotAborted() { - doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled(); - runAndVerifyBackgroundActivityStartsSubtest( - "disallowed_callerIsInstrumentingWithBackgroundActivityStartPrivileges_notAborted", - false, - UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP, - UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, - false, false, false, true, false, false, false, false); - } - - /** - * This test ensures that supported usecases aren't aborted when background starts are - * disallowed. Each scenarios tests one condition that makes them supported in isolation. In - * this case the caller is a device owner. - */ - @Test - public void - testBackgroundActivityStartsDisallowed_callingPackageNameIsDeviceOwnerNotAborted() { - doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled(); - runAndVerifyBackgroundActivityStartsSubtest( - "disallowed_callingPackageNameIsDeviceOwner_notAborted", false, - UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP, - UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, - false, false, false, false, true, false, false, false); - } - - /** - * This test ensures that supported usecases aren't aborted when background starts are - * disallowed. Each scenarios tests one condition that makes them supported in isolation. In - * this case the caller is a affiliated profile owner. - */ - @Test - public void - testBackgroundActivityStartsDisallowed_isAffiliatedProfileOwnerNotAborted() { - doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled(); - runAndVerifyBackgroundActivityStartsSubtest( - "disallowed_callingUidIsAffiliatedProfileOwner_notAborted", false, - UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP, - UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, - false, false, false, false, false, true, false, false); - } - - /** - * This test ensures that supported usecases aren't aborted when background starts are - * disallowed. Each scenarios tests one condition that makes them supported in isolation. In - * this case the caller has the OP_SYSTEM_EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION appop. - */ - @Test - public void testBackgroundActivityStartsDisallowed_callerHasSystemExemptAppOpNotAborted() { - doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled(); - runAndVerifyBackgroundActivityStartsSubtest( - "disallowed_callerHasSystemExemptAppOpNotAborted", false, - UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP, - UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, - false, false, false, false, false, false, false, true); - } - - /** - * This test ensures that supported usecases aren't aborted when background starts are - * disallowed. Each scenarios tests one condition that makes them supported in isolation. In - * this case the caller is an IME. - */ - @Test - public void testBackgroundActivityStartsDisallowed_callingPackageNameIsImeNotAborted() { - doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled(); - setupImeWindow(); - runAndVerifyBackgroundActivityStartsSubtest( - "disallowed_callingPackageNameIsIme_notAborted", false, - CURRENT_IME_UID, false, PROCESS_STATE_BOUND_TOP, - UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, - false, false, false, false, false, false, false, false); - } - - /** - * This test ensures proper logging for BAL_ALLOW_PERMISSION. - */ - @Test - public void testBackgroundActivityStartsAllowed_logging() { - doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled(); - MockitoSession mockingSession = mockitoSession() - .mockStatic(ActivityTaskManagerService.class) - .mockStatic(FrameworkStatsLog.class) - .strictness(Strictness.LENIENT) - .startMocking(); - try { - doReturn(PERMISSION_GRANTED).when(() -> ActivityTaskManagerService.checkPermission( - eq(START_ACTIVITIES_FROM_BACKGROUND), - anyInt(), anyInt())); - runAndVerifyBackgroundActivityStartsSubtest( - "allowed_notAborted", false, - UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP, - UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, - false, true, false, false, false, false, false, false); - verify(() -> FrameworkStatsLog.write(FrameworkStatsLog.BAL_ALLOWED, - "", // activity name - BackgroundActivityStartController.BAL_ALLOW_PERMISSION, - UNIMPORTANT_UID, - UNIMPORTANT_UID2, - BackgroundActivityStartController.BAL_ALLOW_PERMISSION, - true, // opt in - false, // but no explicit opt in - BackgroundActivityStartController.BAL_BLOCK, - true, // opt in - false // but no explicit opt in - )); - } finally { - mockingSession.finishMocking(); - } - } - - /** - * This test ensures proper logging for BAL_ALLOW_PENDING_INTENT, when the PendingIntent sender - * is the only reason BAL is allowed. - */ - @Test - @RequiresFlagsDisabled(com.android.window.flags.Flags.FLAG_BAL_IMPROVED_METRICS) - public void testBackgroundActivityStartsAllowed_loggingOnlyPendingIntentAllowed() { - doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled(); - MockitoSession mockingSession = mockitoSession() - .mockStatic(ActivityTaskManagerService.class) - .mockStatic(FrameworkStatsLog.class) - .mockStatic(PendingIntentRecord.class) - .strictness(Strictness.LENIENT) - .startMocking(); - try { - doReturn(PERMISSION_GRANTED).when(() -> ActivityTaskManagerService.checkPermission( - eq(START_ACTIVITIES_FROM_BACKGROUND), - anyInt(), anyInt())); - doReturn(BackgroundStartPrivileges.allowBackgroundActivityStarts(null)).when( - () -> PendingIntentRecord.getBackgroundStartPrivilegesAllowedByCaller( - anyObject(), anyInt(), anyObject())); - runAndVerifyBackgroundActivityStartsSubtest( - "allowed_notAborted", false, - UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP, - Process.SYSTEM_UID, true, PROCESS_STATE_BOUND_TOP, - false, true, false, false, false, false, false, false, - ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_DENIED); - verify(() -> FrameworkStatsLog.write(FrameworkStatsLog.BAL_ALLOWED, - DEFAULT_COMPONENT_PACKAGE_NAME + "/" + DEFAULT_COMPONENT_PACKAGE_NAME, - BackgroundActivityStartController.BAL_ALLOW_PENDING_INTENT, - UNIMPORTANT_UID, - Process.SYSTEM_UID, - BackgroundActivityStartController.BAL_ALLOW_PERMISSION, - false, // opt in - true, // explicit opt out - BackgroundActivityStartController.BAL_ALLOW_VISIBLE_WINDOW, - true, // opt in - false // but no explicit opt in - )); - } finally { - mockingSession.finishMocking(); - } - } - - /** - * This test ensures proper logging for BAL_ALLOW_PENDING_INTENT, when the PendingIntent sender - * is not the primary reason to allow BAL (but the creator). - */ - @Test - @RequiresFlagsDisabled(com.android.window.flags.Flags.FLAG_BAL_IMPROVED_METRICS) - public void testBackgroundActivityStartsAllowed_loggingPendingIntentAllowed() { - doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled(); - MockitoSession mockingSession = mockitoSession() - .mockStatic(ActivityTaskManagerService.class) - .mockStatic(FrameworkStatsLog.class) - .mockStatic(PendingIntentRecord.class) - .strictness(Strictness.LENIENT) - .startMocking(); - try { - doReturn(PERMISSION_GRANTED).when(() -> ActivityTaskManagerService.checkPermission( - eq(START_ACTIVITIES_FROM_BACKGROUND), - anyInt(), anyInt())); - doReturn(BackgroundStartPrivileges.allowBackgroundActivityStarts(null)).when( - () -> PendingIntentRecord.getBackgroundStartPrivilegesAllowedByCaller( - anyObject(), anyInt(), anyObject())); - runAndVerifyBackgroundActivityStartsSubtest( - "allowed_notAborted", false, - UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP, - Process.SYSTEM_UID, true, PROCESS_STATE_BOUND_TOP, - false, true, false, false, false, false, false, false, - ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED); - verify(() -> FrameworkStatsLog.write(FrameworkStatsLog.BAL_ALLOWED, - "", - BackgroundActivityStartController.BAL_ALLOW_PERMISSION, - UNIMPORTANT_UID, - Process.SYSTEM_UID, - BackgroundActivityStartController.BAL_ALLOW_PERMISSION, - true, // opt in - true, // explicit opt in - BackgroundActivityStartController.BAL_ALLOW_VISIBLE_WINDOW, - true, // opt in - false // but no explicit opt in - )); - } finally { - mockingSession.finishMocking(); - } - } - - private void runAndVerifyBackgroundActivityStartsSubtest(String name, boolean shouldHaveAborted, - int callingUid, boolean callingUidHasVisibleWindow, int callingUidProcState, - int realCallingUid, boolean realCallingUidHasVisibleWindow, int realCallingUidProcState, - boolean hasForegroundActivities, boolean callerIsRecents, - boolean callerIsTempAllowed, - boolean callerIsInstrumentingWithBackgroundActivityStartPrivileges, - boolean isCallingUidDeviceOwner, - boolean isCallingUidAffiliatedProfileOwner, - boolean isPinnedSingleInstance, - boolean hasSystemExemptAppOp) { - runAndVerifyBackgroundActivityStartsSubtest(name, shouldHaveAborted, callingUid, - callingUidHasVisibleWindow, callingUidProcState, realCallingUid, - realCallingUidHasVisibleWindow, realCallingUidProcState, hasForegroundActivities, - callerIsRecents, callerIsTempAllowed, - callerIsInstrumentingWithBackgroundActivityStartPrivileges, - isCallingUidDeviceOwner, isCallingUidAffiliatedProfileOwner, isPinnedSingleInstance, - hasSystemExemptAppOp, - ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED); - } - - private void runAndVerifyBackgroundActivityStartsSubtest(String name, boolean shouldHaveAborted, - int callingUid, boolean callingUidHasVisibleWindow, int callingUidProcState, - int realCallingUid, boolean realCallingUidHasVisibleWindow, int realCallingUidProcState, - boolean hasForegroundActivities, boolean callerIsRecents, - boolean callerIsTempAllowed, - boolean callerIsInstrumentingWithBackgroundActivityStartPrivileges, - boolean isCallingUidDeviceOwner, - boolean isCallingUidAffiliatedProfileOwner, - boolean isPinnedSingleInstance, - boolean hasSystemExemptAppOp, - @BackgroundActivityStartMode int pendingIntentCreatorBackgroundActivityStartMode) { // window visibility - doReturn(callingUidHasVisibleWindow).when(mAtm).hasActiveVisibleWindow(callingUid); - doReturn(realCallingUidHasVisibleWindow).when(mAtm).hasActiveVisibleWindow(realCallingUid); + doReturn(false).when(mAtm).hasActiveVisibleWindow(UNIMPORTANT_UID); + doReturn(false).when(mAtm).hasActiveVisibleWindow(UNIMPORTANT_UID2); // process importance - mAtm.mActiveUids.onUidActive(callingUid, callingUidProcState); - mAtm.mActiveUids.onUidActive(realCallingUid, realCallingUidProcState); + mAtm.mActiveUids.onUidActive(UNIMPORTANT_UID, PROCESS_STATE_BOUND_TOP); + mAtm.mActiveUids.onUidActive(UNIMPORTANT_UID2, PROCESS_STATE_BOUND_TOP); // foreground activities final IApplicationThread caller = mock(IApplicationThread.class); final WindowProcessListener listener = mock(WindowProcessListener.class); final ApplicationInfo ai = new ApplicationInfo(); - ai.uid = callingUid; + ai.uid = UNIMPORTANT_UID; ai.packageName = "com.android.test.package"; - final WindowProcessController callerApp = - spy(new WindowProcessController(mAtm, ai, null, callingUid, -1, null, listener)); - doReturn(hasForegroundActivities).when(callerApp).hasForegroundActivities(); + final WindowProcessController callerApp = spy(new WindowProcessController( + mAtm, ai, null, UNIMPORTANT_UID, -1, null, listener)); + doReturn(false).when(callerApp).hasForegroundActivities(); doReturn(callerApp).when(mAtm).getProcessController(caller); // caller is recents RecentTasks recentTasks = mock(RecentTasks.class); mAtm.mTaskSupervisor.setRecentTasks(recentTasks); - doReturn(callerIsRecents).when(recentTasks).isCallerRecents(callingUid); + doReturn(false).when(recentTasks).isCallerRecents(UNIMPORTANT_UID); // caller is temp allowed - if (callerIsTempAllowed) { - callerApp.addOrUpdateBackgroundStartPrivileges(new Binder(), - BackgroundStartPrivileges.ALLOW_BAL); - } // caller is instrumenting with background activity starts privileges - callerApp.setInstrumenting(callerIsInstrumentingWithBackgroundActivityStartPrivileges, - callerIsInstrumentingWithBackgroundActivityStartPrivileges ? Process.SHELL_UID : -1, - callerIsInstrumentingWithBackgroundActivityStartPrivileges); + callerApp.setInstrumenting(false, -1, false); // callingUid is the device owner - doReturn(isCallingUidDeviceOwner).when(mAtm).isDeviceOwner(callingUid); + doReturn(false).when(mAtm).isDeviceOwner(UNIMPORTANT_UID); // callingUid is the affiliated profile owner - doReturn(isCallingUidAffiliatedProfileOwner).when(mAtm) - .isAffiliatedProfileOwner(callingUid); + doReturn(false).when(mAtm).isAffiliatedProfileOwner(UNIMPORTANT_UID); // caller has OP_SYSTEM_EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION appop - doReturn(hasSystemExemptAppOp ? AppOpsManager.MODE_ALLOWED - : AppOpsManager.MODE_DEFAULT).when(mAppOpsManager).checkOpNoThrow( + doReturn(AppOpsManager.MODE_DEFAULT).when(mAppOpsManager).checkOpNoThrow( eq(AppOpsManager.OP_SYSTEM_EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION), anyInt(), any()); - int launchMode = LAUNCH_MULTIPLE; - if (isPinnedSingleInstance) { - final ActivityRecord baseActivity = - new ActivityBuilder(mAtm).setCreateTask(true).build(); - baseActivity.getRootTask() - .setWindowingMode(WINDOWING_MODE_PINNED); - doReturn(baseActivity).when(mRootWindowContainer).findTask(any(), any()); - launchMode = LAUNCH_SINGLE_INSTANCE; - } + final ActivityRecord baseActivity = new ActivityBuilder(mAtm).setCreateTask(true).build(); + baseActivity.getRootTask().setWindowingMode(WINDOWING_MODE_PINNED); + doReturn(baseActivity).when(mRootWindowContainer).findTask(any(), any()); ActivityOptions rawOptions = ActivityOptions.makeBasic() .setPendingIntentCreatorBackgroundActivityStartMode( - pendingIntentCreatorBackgroundActivityStartMode); + ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED); final ActivityOptions options = spy(rawOptions); ActivityRecord[] outActivity = new ActivityRecord[1]; ActivityStarter starter = prepareStarter( - FLAG_ACTIVITY_NEW_TASK, true, launchMode) + FLAG_ACTIVITY_NEW_TASK, true, LAUNCH_SINGLE_INSTANCE) .setCallingPackage("com.whatever.dude") .setCaller(caller) - .setCallingUid(callingUid) - .setRealCallingUid(realCallingUid) + .setCallingUid(UNIMPORTANT_UID) + .setRealCallingUid(UNIMPORTANT_UID2) .setActivityOptions(new SafeActivityOptions(options)) .setOutActivity(outActivity); - final int result = starter.setReason("testBackgroundActivityStarts_" + name).execute(); - - assertEquals(ActivityStarter.getExternalResult( - shouldHaveAborted ? START_ABORTED : START_SUCCESS), result); - verify(options, times(shouldHaveAborted ? 1 : 0)).abort(); + final int result = starter.setReason("testPinnedSingleInstanceAborted").execute(); + assertEquals(ActivityStarter.getExternalResult(START_ABORTED), result); + verify(options, times(1)).abort(); final ActivityRecord startedActivity = outActivity[0]; if (startedActivity != null && startedActivity.getTask() != null) { 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 4afc8ac6c5994219a75d2c742e70adb9d0599463..366e519fb06391507865596fad5ca6c9f8dc11d9 100644 --- a/services/tests/wmtests/src/com/android/server/wm/BackgroundActivityStartControllerExemptionTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/BackgroundActivityStartControllerExemptionTests.java @@ -29,6 +29,7 @@ import static com.google.common.truth.Truth.assertWithMessage; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import android.app.ActivityOptions; @@ -564,4 +565,136 @@ public class BackgroundActivityStartControllerExemptionTests { assertWithMessage(balState.toString()).that(callerVerdict.getCode()).isEqualTo( BAL_ALLOW_SAW_PERMISSION); } + + @Test + public void testCaller_isRecents() { + 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 + //if (mSupervisor.mRecentTasks.isCallerRecents(state.mCallingUid)) + RecentTasks recentTasks = mock(RecentTasks.class); + when(recentTasks.isCallerRecents(eq(callingUid))).thenReturn(true); + mSupervisor.mRecentTasks = recentTasks; + + // prepare call + PendingIntentRecord originatingPendingIntent = mPendingIntentRecord; + BackgroundStartPrivileges forcedBalByPiSender = BackgroundStartPrivileges.NONE; + Intent intent = TEST_INTENT; + ActivityOptions checkedOptions = mCheckedOptions; + BackgroundActivityStartController.BalState balState = mController.new BalState(callingUid, + callingPid, callingPackage, realCallingUid, realCallingPid, null, + originatingPendingIntent, forcedBalByPiSender, mResultRecord, intent, + checkedOptions); + + // call + BalVerdict callerVerdict = mController.checkBackgroundActivityStartAllowedByCaller( + balState); + balState.setResultForCaller(callerVerdict); + + // assertions + assertWithMessage(balState.toString()).that(callerVerdict.getCode()).isEqualTo( + BAL_ALLOW_ALLOWLISTED_COMPONENT); + } + + @Test + public void testCaller_isDeviceOwner() { + 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.isDeviceOwner(eq(callingUid))).thenReturn(true); + + // prepare call + PendingIntentRecord originatingPendingIntent = mPendingIntentRecord; + BackgroundStartPrivileges forcedBalByPiSender = BackgroundStartPrivileges.NONE; + Intent intent = TEST_INTENT; + ActivityOptions checkedOptions = mCheckedOptions; + BackgroundActivityStartController.BalState balState = mController.new BalState(callingUid, + callingPid, callingPackage, realCallingUid, realCallingPid, null, + originatingPendingIntent, forcedBalByPiSender, mResultRecord, intent, + checkedOptions); + + // call + BalVerdict callerVerdict = mController.checkBackgroundActivityStartAllowedByCaller( + balState); + balState.setResultForCaller(callerVerdict); + + // assertions + assertWithMessage(balState.toString()).that(callerVerdict.getCode()).isEqualTo( + BAL_ALLOW_ALLOWLISTED_COMPONENT); + } + + @Test + public void testCaller_isAffiliatedProfileOwner() { + 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.isAffiliatedProfileOwner(eq(callingUid))).thenReturn(true); + + // prepare call + PendingIntentRecord originatingPendingIntent = mPendingIntentRecord; + BackgroundStartPrivileges forcedBalByPiSender = BackgroundStartPrivileges.NONE; + Intent intent = TEST_INTENT; + ActivityOptions checkedOptions = mCheckedOptions; + BackgroundActivityStartController.BalState balState = mController.new BalState(callingUid, + callingPid, callingPackage, realCallingUid, realCallingPid, null, + originatingPendingIntent, forcedBalByPiSender, mResultRecord, intent, + checkedOptions); + + // call + BalVerdict callerVerdict = mController.checkBackgroundActivityStartAllowedByCaller( + balState); + balState.setResultForCaller(callerVerdict); + + // assertions + assertWithMessage(balState.toString()).that(callerVerdict.getCode()).isEqualTo( + BAL_ALLOW_ALLOWLISTED_COMPONENT); + } + + @Test + public void testCaller_isExemptFromBgStartRestriction() { + 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; + + mDeviceConfig.set("system_exempt_from_activity_bg_start_restriction_enabled", "true"); + AppOpsManager appOpsManager = mock(AppOpsManager.class); + when(mService.getAppOpsManager()).thenReturn(appOpsManager); + when(appOpsManager.checkOpNoThrow(eq( + AppOpsManager.OP_SYSTEM_EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION), + eq(callingUid), eq(callingPackage))).thenReturn(AppOpsManager.MODE_ALLOWED); + + + // prepare call + PendingIntentRecord originatingPendingIntent = mPendingIntentRecord; + BackgroundStartPrivileges forcedBalByPiSender = BackgroundStartPrivileges.NONE; + Intent intent = TEST_INTENT; + ActivityOptions checkedOptions = mCheckedOptions; + BackgroundActivityStartController.BalState balState = mController.new BalState(callingUid, + callingPid, callingPackage, realCallingUid, realCallingPid, null, + originatingPendingIntent, forcedBalByPiSender, mResultRecord, intent, + checkedOptions); + + // call + BalVerdict callerVerdict = mController.checkBackgroundActivityStartAllowedByCaller( + balState); + balState.setResultForCaller(callerVerdict); + + // assertions + assertWithMessage(balState.toString()).that(callerVerdict.getCode()).isEqualTo( + BAL_ALLOW_PERMISSION); + } } diff --git a/services/tests/wmtests/src/com/android/server/wm/BackgroundLaunchProcessControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/BackgroundLaunchProcessControllerTests.java new file mode 100644 index 0000000000000000000000000000000000000000..a4df03447754c67d692445c5c74ea589c25f9d75 --- /dev/null +++ b/services/tests/wmtests/src/com/android/server/wm/BackgroundLaunchProcessControllerTests.java @@ -0,0 +1,189 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.wm; + +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_FOREGROUND; +import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_GRACE_PERIOD; +import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_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.assertThat; + +import android.app.BackgroundStartPrivileges; +import android.content.Context; +import android.os.Binder; +import android.os.IBinder; +import android.platform.test.annotations.Presubmit; + +import androidx.test.filters.SmallTest; + +import com.android.server.wm.BackgroundActivityStartController.BalVerdict; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +/** + * Tests for the {@link BackgroundLaunchProcessController} class. + * + * Build/Install/Run: + * atest WmTests:BackgroundLaunchProcessControllerTests + */ +@SmallTest +@Presubmit +@RunWith(JUnit4.class) +public class BackgroundLaunchProcessControllerTests { + + Set<IBinder> mActivityStartAllowed = new HashSet<>(); + Set<Integer> mHasActiveVisibleWindow = new HashSet<>(); + + BackgroundActivityStartCallback mCallback = new BackgroundActivityStartCallback() { + @Override + public boolean isActivityStartAllowed(Collection<IBinder> tokens, int uid, + String packageName) { + for (IBinder token : tokens) { + if (token == null || mActivityStartAllowed.contains(token)) { + return true; + } + } + return false; + } + + @Override + public boolean canCloseSystemDialogs(Collection<IBinder> tokens, int uid) { + return false; + } + }; + BackgroundLaunchProcessController mController = new BackgroundLaunchProcessController( + mHasActiveVisibleWindow::contains, mCallback); + + int mPid = 123; + int mUid = 234; + String mPackageName = "package.name"; + int mAppSwitchState = APP_SWITCH_DISALLOW; + boolean mIsCheckingForFgsStart = false; + boolean mHasActivityInVisibleTask = false; + boolean mHasBackgroundActivityStartPrivileges = false; + long mLastStopAppSwitchesTime = 0L; + long mLastActivityLaunchTime = 0L; + long mLastActivityFinishTime = 0L; + + @Test + public void testNothingAllows() { + BalVerdict balVerdict = mController.areBackgroundActivityStartsAllowed( + mPid, mUid, mPackageName, + mAppSwitchState, mIsCheckingForFgsStart, + mHasActivityInVisibleTask, mHasBackgroundActivityStartPrivileges, + mLastStopAppSwitchesTime, mLastActivityLaunchTime, + mLastActivityFinishTime); + assertThat(balVerdict.getCode()).isEqualTo(BAL_BLOCK); + } + + @Test + public void testInstrumenting() { + mHasBackgroundActivityStartPrivileges = true; + BalVerdict balVerdict = mController.areBackgroundActivityStartsAllowed( + mPid, mUid, mPackageName, + mAppSwitchState, mIsCheckingForFgsStart, + mHasActivityInVisibleTask, mHasBackgroundActivityStartPrivileges, + mLastStopAppSwitchesTime, mLastActivityLaunchTime, + mLastActivityFinishTime); + assertThat(balVerdict.getCode()).isEqualTo(BAL_ALLOW_PERMISSION); + } + + @Test + public void testAllowedByTokenNoCallback() { + mController = new BackgroundLaunchProcessController(mHasActiveVisibleWindow::contains, + null); + Binder token = new Binder(); + mActivityStartAllowed.add(token); + mController.addOrUpdateAllowBackgroundStartPrivileges(token, + BackgroundStartPrivileges.ALLOW_BAL); + BalVerdict balVerdict = mController.areBackgroundActivityStartsAllowed( + mPid, mUid, mPackageName, + mAppSwitchState, mIsCheckingForFgsStart, + mHasActivityInVisibleTask, mHasBackgroundActivityStartPrivileges, + mLastStopAppSwitchesTime, mLastActivityLaunchTime, + mLastActivityFinishTime); + assertThat(balVerdict.getCode()).isEqualTo(BAL_ALLOW_PERMISSION); + } + + @Test + public void testAllowedByToken() { + Binder token = new Binder(); + mActivityStartAllowed.add(token); + mController.addOrUpdateAllowBackgroundStartPrivileges(token, + BackgroundStartPrivileges.ALLOW_BAL); + BalVerdict balVerdict = mController.areBackgroundActivityStartsAllowed( + mPid, mUid, mPackageName, + mAppSwitchState, mIsCheckingForFgsStart, + mHasActivityInVisibleTask, mHasBackgroundActivityStartPrivileges, + mLastStopAppSwitchesTime, mLastActivityLaunchTime, + mLastActivityFinishTime); + assertThat(balVerdict.getCode()).isEqualTo(BAL_ALLOW_PERMISSION); + } + + @Test + public void testBoundByForeground() { + mAppSwitchState = APP_SWITCH_ALLOW; + mController.addBoundClientUid(999, "visible.package", Context.BIND_ALLOW_ACTIVITY_STARTS); + mHasActiveVisibleWindow.add(999); + BalVerdict balVerdict = mController.areBackgroundActivityStartsAllowed( + mPid, mUid, mPackageName, + mAppSwitchState, mIsCheckingForFgsStart, + mHasActivityInVisibleTask, mHasBackgroundActivityStartPrivileges, + mLastStopAppSwitchesTime, mLastActivityLaunchTime, + mLastActivityFinishTime); + assertThat(balVerdict.getCode()).isEqualTo(BAL_ALLOW_VISIBLE_WINDOW); + } + + @Test + public void testForegroundTask() { + mAppSwitchState = APP_SWITCH_ALLOW; + mHasActivityInVisibleTask = true; + BalVerdict balVerdict = mController.areBackgroundActivityStartsAllowed( + mPid, mUid, mPackageName, + mAppSwitchState, mIsCheckingForFgsStart, + mHasActivityInVisibleTask, mHasBackgroundActivityStartPrivileges, + mLastStopAppSwitchesTime, mLastActivityLaunchTime, + mLastActivityFinishTime); + assertThat(balVerdict.getCode()).isEqualTo(BAL_ALLOW_FOREGROUND); + } + + @Test + public void testGracePeriod() { + mAppSwitchState = APP_SWITCH_ALLOW; + long now = System.currentTimeMillis(); + mLastStopAppSwitchesTime = now - 10000; + mLastActivityLaunchTime = now - 9000; + mLastActivityFinishTime = now - 100; + BalVerdict balVerdict = mController.areBackgroundActivityStartsAllowed( + mPid, mUid, mPackageName, + mAppSwitchState, mIsCheckingForFgsStart, + mHasActivityInVisibleTask, mHasBackgroundActivityStartPrivileges, + mLastStopAppSwitchesTime, mLastActivityLaunchTime, + mLastActivityFinishTime); + assertThat(balVerdict.getCode()).isEqualTo(BAL_ALLOW_GRACE_PERIOD); + } +}