1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License 15 */ 16 17 package com.android.server.wm; 18 19 import static android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND; 20 import static android.app.Activity.RESULT_CANCELED; 21 import static android.app.ActivityManager.PROCESS_STATE_BOUND_TOP; 22 import static android.app.ActivityManager.PROCESS_STATE_TOP; 23 import static android.app.ActivityManager.START_ABORTED; 24 import static android.app.ActivityManager.START_CANCELED; 25 import static android.app.ActivityManager.START_CLASS_NOT_FOUND; 26 import static android.app.ActivityManager.START_DELIVERED_TO_TOP; 27 import static android.app.ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT; 28 import static android.app.ActivityManager.START_INTENT_NOT_RESOLVED; 29 import static android.app.ActivityManager.START_NOT_VOICE_COMPATIBLE; 30 import static android.app.ActivityManager.START_PERMISSION_DENIED; 31 import static android.app.ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION; 32 import static android.app.ActivityManager.START_SUCCESS; 33 import static android.app.ActivityManager.START_TASK_TO_FRONT; 34 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; 35 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; 36 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; 37 import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK; 38 import static android.content.Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT; 39 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; 40 import static android.content.Intent.FLAG_ACTIVITY_REORDER_TO_FRONT; 41 import static android.content.Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED; 42 import static android.content.Intent.FLAG_ACTIVITY_SINGLE_TOP; 43 import static android.content.pm.ActivityInfo.FLAG_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING; 44 import static android.content.pm.ActivityInfo.LAUNCH_MULTIPLE; 45 import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE; 46 import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK; 47 import static android.content.pm.PackageManager.PERMISSION_GRANTED; 48 import static android.os.Process.SYSTEM_UID; 49 50 import static com.android.dx.mockito.inline.extended.ExtendedMockito.clearInvocations; 51 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer; 52 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; 53 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; 54 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; 55 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; 56 import static com.android.dx.mockito.inline.extended.ExtendedMockito.never; 57 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy; 58 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; 59 import static com.android.dx.mockito.inline.extended.ExtendedMockito.times; 60 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; 61 import static com.android.server.wm.ActivityStarter.canEmbedActivity; 62 import static com.android.server.wm.TaskFragment.EMBEDDING_ALLOWED; 63 import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_MIN_DIMENSION_VIOLATION; 64 import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_NEW_TASK; 65 import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_UNTRUSTED_HOST; 66 import static com.android.server.wm.WindowContainer.POSITION_BOTTOM; 67 import static com.android.server.wm.WindowContainer.POSITION_TOP; 68 import static com.android.server.wm.WindowTestsBase.ActivityBuilder.DEFAULT_FAKE_UID; 69 70 import static com.google.common.truth.Truth.assertThat; 71 72 import static org.junit.Assert.assertEquals; 73 import static org.junit.Assert.assertFalse; 74 import static org.junit.Assert.assertNotEquals; 75 import static org.junit.Assert.assertNotNull; 76 import static org.junit.Assert.assertNull; 77 import static org.junit.Assert.assertTrue; 78 import static org.mockito.ArgumentMatchers.any; 79 import static org.mockito.ArgumentMatchers.anyBoolean; 80 import static org.mockito.ArgumentMatchers.anyInt; 81 import static org.mockito.ArgumentMatchers.anyLong; 82 import static org.mockito.ArgumentMatchers.anyObject; 83 import static org.mockito.ArgumentMatchers.anyString; 84 import static org.mockito.ArgumentMatchers.eq; 85 import static org.mockito.ArgumentMatchers.notNull; 86 87 import android.app.ActivityOptions; 88 import android.app.AppOpsManager; 89 import android.app.BackgroundStartPrivileges; 90 import android.app.IApplicationThread; 91 import android.app.PictureInPictureParams; 92 import android.content.ComponentName; 93 import android.content.Intent; 94 import android.content.pm.ActivityInfo; 95 import android.content.pm.ActivityInfo.WindowLayout; 96 import android.content.pm.ApplicationInfo; 97 import android.content.pm.IPackageManager; 98 import android.content.pm.PackageManagerInternal; 99 import android.content.pm.SigningDetails; 100 import android.graphics.Rect; 101 import android.os.Binder; 102 import android.os.IBinder; 103 import android.os.Process; 104 import android.os.RemoteException; 105 import android.os.UserHandle; 106 import android.platform.test.annotations.Presubmit; 107 import android.provider.DeviceConfig; 108 import android.service.voice.IVoiceInteractionSession; 109 import android.util.Pair; 110 import android.util.Size; 111 import android.view.Gravity; 112 import android.view.RemoteAnimationAdapter; 113 import android.window.TaskFragmentOrganizerToken; 114 115 import androidx.test.filters.SmallTest; 116 117 import com.android.compatibility.common.util.DeviceConfigStateHelper; 118 import com.android.internal.util.FrameworkStatsLog; 119 import com.android.server.am.PendingIntentRecord; 120 import com.android.server.pm.pkg.AndroidPackage; 121 import com.android.server.wm.LaunchParamsController.LaunchParamsModifier; 122 import com.android.server.wm.utils.MockTracker; 123 124 import org.junit.After; 125 import org.junit.Before; 126 import org.junit.Ignore; 127 import org.junit.Test; 128 import org.junit.runner.RunWith; 129 import org.mockito.MockitoSession; 130 import org.mockito.quality.Strictness; 131 132 import java.util.Arrays; 133 import java.util.HashSet; 134 import java.util.Set; 135 136 /** 137 * Tests for the {@link ActivityStarter} class. 138 * 139 * Build/Install/Run: 140 * atest WmTests:ActivityStarterTests 141 */ 142 @SmallTest 143 @Presubmit 144 @RunWith(WindowTestRunner.class) 145 public class ActivityStarterTests extends WindowTestsBase { 146 147 private static final int PRECONDITION_NO_CALLER_APP = 1; 148 private static final int PRECONDITION_NO_INTENT_COMPONENT = 1 << 1; 149 private static final int PRECONDITION_NO_ACTIVITY_INFO = 1 << 2; 150 private static final int PRECONDITION_SOURCE_PRESENT = 1 << 3; 151 private static final int PRECONDITION_REQUEST_CODE = 1 << 4; 152 private static final int PRECONDITION_SOURCE_VOICE_SESSION = 1 << 5; 153 private static final int PRECONDITION_NO_VOICE_SESSION_SUPPORT = 1 << 6; 154 private static final int PRECONDITION_DIFFERENT_UID = 1 << 7; 155 private static final int PRECONDITION_ACTIVITY_SUPPORTS_INTENT_EXCEPTION = 1 << 8; 156 private static final int PRECONDITION_CANNOT_START_ANY_ACTIVITY = 1 << 9; 157 private static final int FAKE_CALLING_UID = 666; 158 private static final int FAKE_REAL_CALLING_UID = 667; 159 private static final String FAKE_CALLING_PACKAGE = "com.whatever.dude"; 160 private static final int UNIMPORTANT_UID = 12345; 161 private static final int UNIMPORTANT_UID2 = 12346; 162 private static final int SDK_SANDBOX_UID = Process.toSdkSandboxUid(UNIMPORTANT_UID); 163 private static final int SECONDARY_USER_SDK_SANDBOX_UID = 164 UserHandle.getUid(10, SDK_SANDBOX_UID); 165 private static final int CURRENT_IME_UID = 12347; 166 167 protected final DeviceConfigStateHelper mDeviceConfig = new DeviceConfigStateHelper( 168 DeviceConfig.NAMESPACE_WINDOW_MANAGER); 169 170 private ActivityStartController mController; 171 private ActivityMetricsLogger mActivityMetricsLogger; 172 private PackageManagerInternal mMockPackageManager; 173 private AppOpsManager mAppOpsManager; 174 175 @Before setUp()176 public void setUp() throws Exception { 177 mController = mock(ActivityStartController.class); 178 BackgroundActivityStartController balController = 179 new BackgroundActivityStartController(mAtm, mSupervisor); 180 doReturn(balController).when(mController).getBackgroundActivityLaunchController(); 181 mActivityMetricsLogger = mock(ActivityMetricsLogger.class); 182 clearInvocations(mActivityMetricsLogger); 183 mAppOpsManager = mAtm.getAppOpsManager(); 184 doReturn(AppOpsManager.MODE_DEFAULT).when(mAppOpsManager).checkOpNoThrow( 185 eq(AppOpsManager.OP_SYSTEM_EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION), 186 anyInt(), any()); 187 } 188 189 @After tearDown()190 public void tearDown() throws Exception { 191 mDeviceConfig.close(); 192 } 193 194 @Test testStartActivityPreconditions()195 public void testStartActivityPreconditions() { 196 verifyStartActivityPreconditions(PRECONDITION_NO_CALLER_APP, START_PERMISSION_DENIED); 197 verifyStartActivityPreconditions(PRECONDITION_NO_INTENT_COMPONENT, 198 START_INTENT_NOT_RESOLVED); 199 verifyStartActivityPreconditions(PRECONDITION_NO_ACTIVITY_INFO, START_CLASS_NOT_FOUND); 200 verifyStartActivityPreconditions(PRECONDITION_SOURCE_PRESENT | PRECONDITION_REQUEST_CODE, 201 Intent.FLAG_ACTIVITY_FORWARD_RESULT, START_FORWARD_AND_REQUEST_CONFLICT); 202 verifyStartActivityPreconditions( 203 PRECONDITION_SOURCE_PRESENT | PRECONDITION_NO_VOICE_SESSION_SUPPORT 204 | PRECONDITION_SOURCE_VOICE_SESSION | PRECONDITION_DIFFERENT_UID, 205 START_NOT_VOICE_COMPATIBLE); 206 verifyStartActivityPreconditions( 207 PRECONDITION_SOURCE_PRESENT | PRECONDITION_NO_VOICE_SESSION_SUPPORT 208 | PRECONDITION_SOURCE_VOICE_SESSION | PRECONDITION_DIFFERENT_UID 209 | PRECONDITION_ACTIVITY_SUPPORTS_INTENT_EXCEPTION, 210 START_NOT_VOICE_COMPATIBLE); 211 verifyStartActivityPreconditions(PRECONDITION_CANNOT_START_ANY_ACTIVITY, START_ABORTED); 212 } 213 containsConditions(int preconditions, int mask)214 private static boolean containsConditions(int preconditions, int mask) { 215 return (preconditions & mask) == mask; 216 } 217 verifyStartActivityPreconditions(int preconditions, int expectedResult)218 private void verifyStartActivityPreconditions(int preconditions, int expectedResult) { 219 verifyStartActivityPreconditions(preconditions, 0 /*launchFlags*/, expectedResult); 220 } 221 verifyStartActivityPreconditions(int preconditions, int launchFlags, int expectedResult)222 private void verifyStartActivityPreconditions(int preconditions, int launchFlags, 223 int expectedResult) { 224 // We track mocks created here because this is used in a single test 225 // (testStartActivityPreconditions) as a specific case, and mocks created inside it won't be 226 // used for other cases. To avoid extensive memory usage, we clean up all used mocks after 227 // each case. This is necessary because usually we only clean up mocks after a test 228 // finishes, but this test creates too many mocks that the intermediate memory usage can be 229 // ~0.8 GiB and thus very susceptible to OutOfMemoryException. 230 try (MockTracker tracker = new MockTracker()) { 231 verifyStartActivityPreconditionsUntracked(preconditions, launchFlags, expectedResult); 232 } 233 } 234 235 /** 236 * Excercises how the {@link ActivityStarter} reacts to various preconditions. The caller 237 * provides a bitmask of all the set conditions (such as {@link #PRECONDITION_NO_CALLER_APP}) 238 * and the launch flags specified in the intent. The method constructs a call to 239 * {@link ActivityStarter#execute} based on these preconditions and ensures the result matches 240 * the expected. It is important to note that the method also checks side effects of the start, 241 * such as ensuring {@link ActivityOptions#abort()} is called in the relevant scenarios. 242 * 243 * @param preconditions A bitmask representing the preconditions for the launch 244 * @param launchFlags The launch flags to be provided by the launch {@link Intent}. 245 * @param expectedResult The expected result from the launch. 246 */ verifyStartActivityPreconditionsUntracked(int preconditions, int launchFlags, int expectedResult)247 private void verifyStartActivityPreconditionsUntracked(int preconditions, int launchFlags, 248 int expectedResult) { 249 final ActivityTaskManagerService service = mAtm; 250 final IPackageManager packageManager = mock(IPackageManager.class); 251 252 final ActivityStarter starter = 253 new ActivityStarter( 254 mController, 255 service, 256 service.mTaskSupervisor, 257 mock(ActivityStartInterceptor.class)); 258 prepareStarter(launchFlags); 259 final IApplicationThread caller = mock(IApplicationThread.class); 260 final WindowProcessListener listener = mock(WindowProcessListener.class); 261 262 final ApplicationInfo ai = new ApplicationInfo(); 263 ai.packageName = "com.android.test.package"; 264 final WindowProcessController wpc = 265 containsConditions(preconditions, PRECONDITION_NO_CALLER_APP) 266 ? null 267 : new WindowProcessController(service, ai, null, 0, -1, null, listener); 268 doReturn(wpc).when(service).getProcessController(any()); 269 270 final Intent intent = new Intent(); 271 intent.setFlags(launchFlags); 272 273 final ActivityInfo aInfo = containsConditions(preconditions, PRECONDITION_NO_ACTIVITY_INFO) 274 ? null : new ActivityInfo(); 275 276 IVoiceInteractionSession voiceSession = 277 containsConditions(preconditions, PRECONDITION_SOURCE_VOICE_SESSION) 278 ? mock(IVoiceInteractionSession.class) : null; 279 280 // Create source token 281 final ActivityBuilder builder = new ActivityBuilder(service).setTask( 282 new TaskBuilder(service.mTaskSupervisor) 283 .setVoiceSession(voiceSession) 284 .setCreateParentTask(true) 285 .build()); 286 287 if (aInfo != null) { 288 aInfo.applicationInfo = new ApplicationInfo(); 289 aInfo.applicationInfo.packageName = 290 ActivityBuilder.getDefaultComponent().getPackageName(); 291 } 292 293 // Offset uid by one from {@link ActivityInfo} to simulate different uids. 294 if (containsConditions(preconditions, PRECONDITION_DIFFERENT_UID)) { 295 builder.setUid(aInfo.applicationInfo.uid + 1); 296 } 297 298 final ActivityRecord source = builder.build(); 299 300 if (!containsConditions(preconditions, PRECONDITION_NO_INTENT_COMPONENT)) { 301 intent.setComponent(source.mActivityComponent); 302 } 303 304 if (containsConditions(preconditions, PRECONDITION_CANNOT_START_ANY_ACTIVITY)) { 305 doReturn(false).when(service.mTaskSupervisor).checkStartAnyActivityPermission( 306 any(), any(), any(), anyInt(), anyInt(), anyInt(), any(), any(), 307 anyBoolean(), anyBoolean(), any(), any(), any()); 308 } 309 310 try { 311 if (containsConditions(preconditions, 312 PRECONDITION_ACTIVITY_SUPPORTS_INTENT_EXCEPTION)) { 313 doAnswer((inv) -> { 314 throw new RemoteException(); 315 }).when(packageManager).activitySupportsIntentAsUser( 316 eq(source.mActivityComponent), eq(intent), any(), anyInt()); 317 } else { 318 doReturn(!containsConditions(preconditions, PRECONDITION_NO_VOICE_SESSION_SUPPORT)) 319 .when(packageManager).activitySupportsIntentAsUser( 320 eq(source.mActivityComponent), eq(intent), any(), anyInt()); 321 } 322 } catch (RemoteException e) { 323 } 324 325 final IBinder resultTo = containsConditions(preconditions, PRECONDITION_SOURCE_PRESENT) 326 || containsConditions(preconditions, PRECONDITION_SOURCE_VOICE_SESSION) 327 ? source.token : null; 328 329 final int requestCode = containsConditions(preconditions, PRECONDITION_REQUEST_CODE) 330 ? 1 : 0; 331 332 final int result = starter.setCaller(caller) 333 .setIntent(intent) 334 .setActivityInfo(aInfo) 335 .setResultTo(resultTo) 336 .setRequestCode(requestCode) 337 .setReason("testLaunchActivityPermissionDenied") 338 .execute(); 339 340 // In some cases the expected result internally is different than the published result. We 341 // must use ActivityStarter#getExternalResult to translate. 342 assertEquals(ActivityStarter.getExternalResult(expectedResult), result); 343 344 // Ensure that {@link ActivityOptions} are aborted with unsuccessful result. 345 if (expectedResult != START_SUCCESS) { 346 final ActivityStarter optionStarter = new ActivityStarter(mController, mAtm, 347 mAtm.mTaskSupervisor, mock(ActivityStartInterceptor.class)); 348 final ActivityOptions options = spy(ActivityOptions.makeBasic()); 349 350 final int optionResult = optionStarter.setCaller(caller) 351 .setIntent(intent) 352 .setActivityInfo(aInfo) 353 .setResultTo(resultTo) 354 .setRequestCode(requestCode) 355 .setReason("testLaunchActivityPermissionDenied") 356 .setActivityOptions(new SafeActivityOptions(options)) 357 .execute(); 358 verify(options, times(1)).abort(); 359 } 360 } 361 prepareStarter(@ntent.Flags int launchFlags)362 private ActivityStarter prepareStarter(@Intent.Flags int launchFlags) { 363 return prepareStarter(launchFlags, true /* mockGetRootTask */, LAUNCH_MULTIPLE); 364 } 365 prepareStarter(@ntent.Flags int launchFlags, boolean mockGetRootTask)366 private ActivityStarter prepareStarter(@Intent.Flags int launchFlags, 367 boolean mockGetRootTask) { 368 return prepareStarter(launchFlags, mockGetRootTask, LAUNCH_MULTIPLE); 369 } 370 setupImeWindow()371 private void setupImeWindow() { 372 final WindowState imeWindow = createWindow(null, W_INPUT_METHOD, 373 "mImeWindow", CURRENT_IME_UID); 374 mDisplayContent.mInputMethodWindow = imeWindow; 375 } 376 377 /** 378 * Creates a {@link ActivityStarter} with default parameters and necessary mocks. 379 * 380 * @param launchFlags The intent flags to launch activity. 381 * @param mockGetRootTask Whether to mock {@link RootWindowContainer#getOrCreateRootTask} for 382 * always launching to the testing stack. Set to false when allowing 383 * the activity can be launched to any stack that is decided by real 384 * implementation. 385 * @return A {@link ActivityStarter} with default setup. 386 */ prepareStarter(@ntent.Flags int launchFlags, boolean mockGetRootTask, int launchMode)387 private ActivityStarter prepareStarter(@Intent.Flags int launchFlags, 388 boolean mockGetRootTask, int launchMode) { 389 // always allow test to start activity. 390 doReturn(true).when(mSupervisor).checkStartAnyActivityPermission( 391 any(), any(), any(), anyInt(), anyInt(), anyInt(), any(), any(), 392 anyBoolean(), anyBoolean(), any(), any(), any()); 393 394 if (mockGetRootTask) { 395 // Instrument the stack and task used. 396 final Task stack = mRootWindowContainer.getDefaultTaskDisplayArea() 397 .createRootTask(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, 398 true /* onTop */); 399 400 // Direct starter to use spy stack. 401 doReturn(stack).when(mRootWindowContainer) 402 .getOrCreateRootTask(any(), any(), any(), anyBoolean()); 403 doReturn(stack).when(mRootWindowContainer).getOrCreateRootTask(any(), any(), any(), 404 any(), anyBoolean(), any(), anyInt()); 405 } 406 407 // Set up mock package manager internal and make sure no unmocked methods are called 408 mMockPackageManager = mock(PackageManagerInternal.class, 409 invocation -> { 410 throw new RuntimeException("Not stubbed"); 411 }); 412 doReturn(null).when(mMockPackageManager).getDefaultHomeActivity(anyInt()); 413 doReturn(mMockPackageManager).when(mAtm).getPackageManagerInternalLocked(); 414 doReturn(false).when(mMockPackageManager).isInstantAppInstallerComponent(any()); 415 doReturn(null).when(mMockPackageManager).resolveIntent(any(), any(), anyLong(), anyLong(), 416 anyInt(), anyBoolean(), anyInt()); 417 doReturn(null).when(mMockPackageManager).resolveIntentExported(any(), any(), 418 anyLong(), anyLong(), anyInt(), anyBoolean(), anyInt(), anyInt()); 419 doReturn(new ComponentName("", "")).when(mMockPackageManager).getSystemUiServiceComponent(); 420 421 // Never review permissions 422 doReturn(false).when(mMockPackageManager).isPermissionsReviewRequired(any(), anyInt()); 423 doNothing().when(mMockPackageManager).grantImplicitAccess( 424 anyInt(), any(), anyInt(), anyInt(), anyBoolean()); 425 doNothing().when(mMockPackageManager).notifyPackageUse(anyString(), anyInt()); 426 427 final Intent intent = new Intent(); 428 intent.addFlags(launchFlags); 429 intent.setComponent(ActivityBuilder.getDefaultComponent()); 430 431 final ActivityInfo info = new ActivityInfo(); 432 433 info.applicationInfo = new ApplicationInfo(); 434 info.applicationInfo.packageName = ActivityBuilder.getDefaultComponent().getPackageName(); 435 info.launchMode = launchMode; 436 437 return new ActivityStarter(mController, mAtm, 438 mAtm.mTaskSupervisor, mock(ActivityStartInterceptor.class)) 439 .setIntent(intent) 440 .setActivityInfo(info); 441 } 442 443 /** 444 * Ensures that values specified at launch time are passed to {@link LaunchParamsModifier} 445 * when we are laying out a new task. 446 */ 447 @Test testCreateTaskLayout()448 public void testCreateTaskLayout() { 449 // modifier for validating passed values. 450 final LaunchParamsModifier modifier = mock(LaunchParamsModifier.class); 451 mAtm.mTaskSupervisor.getLaunchParamsController().registerModifier(modifier); 452 453 // add custom values to activity info to make unique. 454 final ActivityInfo info = new ActivityInfo(); 455 final Rect launchBounds = new Rect(0, 0, 20, 30); 456 457 final WindowLayout windowLayout = 458 new WindowLayout(10, .5f, 20, 1.0f, Gravity.NO_GRAVITY, 1, 1); 459 460 info.windowLayout = windowLayout; 461 info.applicationInfo = new ApplicationInfo(); 462 info.applicationInfo.packageName = ActivityBuilder.getDefaultComponent().getPackageName(); 463 464 // create starter. 465 final ActivityStarter optionStarter = prepareStarter(0 /* launchFlags */); 466 467 final ActivityOptions options = ActivityOptions.makeBasic(); 468 options.setLaunchBounds(launchBounds); 469 470 // run starter. 471 optionStarter 472 .setReason("testCreateTaskLayout") 473 .setActivityInfo(info) 474 .setActivityOptions(new SafeActivityOptions(options)) 475 .execute(); 476 477 // verify that values are passed to the modifier. Values are passed thrice -- two for 478 // setting initial state, another when task is created. 479 verify(modifier, times(3)).onCalculate(any(), eq(windowLayout), any(), any(), eq(options), 480 any(), anyInt(), any(), any()); 481 } 482 483 /** 484 * This test ensures that if the intent is being delivered to a split-screen unfocused task 485 * while it already on top, reports it as delivering to top. 486 */ 487 @Test testSplitScreenDeliverToTop()488 public void testSplitScreenDeliverToTop() { 489 final ActivityStarter starter = prepareStarter( 490 FLAG_ACTIVITY_RESET_TASK_IF_NEEDED | FLAG_ACTIVITY_SINGLE_TOP, 491 false /* mockGetRootTask */); 492 final Pair<ActivityRecord, ActivityRecord> activities = createActivitiesInSplit(); 493 final ActivityRecord splitPrimaryFocusActivity = activities.first; 494 final ActivityRecord splitSecondReusableActivity = activities.second; 495 496 // Set focus back to primary. 497 splitPrimaryFocusActivity.moveFocusableActivityToTop("testSplitScreenDeliverToTop"); 498 499 // Start activity and delivered new intent. 500 starter.getIntent().setComponent(splitSecondReusableActivity.mActivityComponent); 501 doReturn(splitSecondReusableActivity).when(mRootWindowContainer).findTask(any(), any()); 502 final int result = starter.setReason("testSplitScreenDeliverToTop").execute(); 503 504 // Ensure result is delivering intent to top. 505 assertEquals(START_DELIVERED_TO_TOP, result); 506 } 507 508 /** 509 * This test ensures that if the intent is being delivered to a split-screen unfocused task 510 * reports it is brought to front instead of delivering to top. 511 */ 512 @Test testSplitScreenTaskToFront()513 public void testSplitScreenTaskToFront() { 514 final ActivityStarter starter = prepareStarter( 515 FLAG_ACTIVITY_RESET_TASK_IF_NEEDED | FLAG_ACTIVITY_SINGLE_TOP, false); 516 final Pair<ActivityRecord, ActivityRecord> activities = createActivitiesInSplit(); 517 final ActivityRecord splitPrimaryFocusActivity = activities.first; 518 final ActivityRecord splitSecondReusableActivity = activities.second; 519 final ActivityRecord splitSecondTopActivity = new ActivityBuilder(mAtm).setCreateTask(true) 520 .setParentTask(splitSecondReusableActivity.getRootTask()).build(); 521 assertTrue(splitSecondTopActivity.inMultiWindowMode()); 522 523 // Let primary stack has focus. 524 splitPrimaryFocusActivity.moveFocusableActivityToTop("testSplitScreenTaskToFront"); 525 526 // Start activity and delivered new intent. 527 starter.getIntent().setComponent(splitSecondReusableActivity.mActivityComponent); 528 doReturn(splitSecondReusableActivity).when(mRootWindowContainer).findTask(any(), any()); 529 final int result = starter.setReason("testSplitScreenMoveToFront").execute(); 530 531 // Ensure result is moving task to front. 532 assertEquals(START_TASK_TO_FRONT, result); 533 } 534 535 /** Returns 2 activities. The first is in primary and the second is in secondary. */ createActivitiesInSplit()536 private Pair<ActivityRecord, ActivityRecord> createActivitiesInSplit() { 537 final TestSplitOrganizer splitOrg = new TestSplitOrganizer(mAtm); 538 // The fullscreen windowing mode activity will be moved to split-secondary by 539 // TestSplitOrganizer when a split-primary task appears. 540 final ActivityRecord splitPrimaryActivity = new TaskBuilder(mSupervisor) 541 .setParentTask(splitOrg.mPrimary) 542 .setCreateActivity(true) 543 .build() 544 .getTopMostActivity(); 545 final ActivityRecord splitSecondActivity = new TaskBuilder(mSupervisor) 546 .setParentTask(splitOrg.mSecondary) 547 .setCreateActivity(true) 548 .build() 549 .getTopMostActivity(); 550 551 splitPrimaryActivity.setVisibleRequested(true); 552 splitSecondActivity.setVisibleRequested(true); 553 554 assertEquals(splitOrg.mPrimary, splitPrimaryActivity.getRootTask()); 555 assertEquals(splitOrg.mSecondary, splitSecondActivity.getRootTask()); 556 return Pair.create(splitPrimaryActivity, splitSecondActivity); 557 } 558 559 @Test testMoveVisibleTaskToFront()560 public void testMoveVisibleTaskToFront() { 561 final ActivityRecord activity = new TaskBuilder(mSupervisor) 562 .setCreateActivity(true).build().getTopMostActivity(); 563 final ActivityRecord translucentActivity = new TaskBuilder(mSupervisor) 564 .setCreateActivity(true).build().getTopMostActivity(); 565 assertTrue(activity.isVisibleRequested()); 566 567 final ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK, 568 false /* mockGetRootTask */); 569 starter.getIntent().setComponent(activity.mActivityComponent); 570 final int result = starter.setReason("testMoveVisibleTaskToFront").execute(); 571 572 assertEquals(START_TASK_TO_FRONT, result); 573 assertEquals(1, activity.compareTo(translucentActivity)); 574 } 575 576 /** 577 * Tests activity is cleaned up properly in a task mode violation. 578 */ 579 @Test testTaskModeViolation()580 public void testTaskModeViolation() { 581 final DisplayContent display = mAtm.mRootWindowContainer.getDefaultDisplay(); 582 display.removeAllTasks(); 583 assertNoTasks(display); 584 585 final ActivityStarter starter = prepareStarter(0); 586 587 final LockTaskController lockTaskController = mAtm.getLockTaskController(); 588 doReturn(true).when(lockTaskController).isNewTaskLockTaskModeViolation(any()); 589 590 final int result = starter.setReason("testTaskModeViolation").execute(); 591 592 assertEquals(START_RETURN_LOCK_TASK_MODE_VIOLATION, result); 593 assertNoTasks(display); 594 } 595 assertNoTasks(DisplayContent display)596 private void assertNoTasks(DisplayContent display) { 597 display.forAllRootTasks(rootTask -> { 598 assertFalse(rootTask.hasChild()); 599 }); 600 } 601 602 /** 603 * This test ensures that activity starts are not being logged when the logging is disabled. 604 */ 605 @Test testActivityStartsLogging_noLoggingWhenDisabled()606 public void testActivityStartsLogging_noLoggingWhenDisabled() { 607 doReturn(false).when(mAtm).isActivityStartsLoggingEnabled(); 608 doReturn(mActivityMetricsLogger).when(mAtm.mTaskSupervisor).getActivityMetricsLogger(); 609 610 ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK); 611 starter.setReason("testActivityStartsLogging_noLoggingWhenDisabled").execute(); 612 613 // verify logging wasn't done 614 verify(mActivityMetricsLogger, never()).logAbortedBgActivityStart(any(), any(), anyInt(), 615 any(), anyInt(), anyBoolean(), anyInt(), anyInt(), anyBoolean(), anyBoolean()); 616 } 617 618 /** 619 * This test ensures that activity starts are being logged when the logging is enabled. 620 */ 621 @Test testActivityStartsLogging_logsWhenEnabled()622 public void testActivityStartsLogging_logsWhenEnabled() { 623 // note: conveniently this package doesn't have any activity visible 624 doReturn(true).when(mAtm).isActivityStartsLoggingEnabled(); 625 doReturn(mActivityMetricsLogger).when(mAtm.mTaskSupervisor).getActivityMetricsLogger(); 626 627 ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK) 628 .setCallingUid(FAKE_CALLING_UID) 629 .setRealCallingUid(FAKE_REAL_CALLING_UID) 630 .setCallingPackage(FAKE_CALLING_PACKAGE) 631 .setOriginatingPendingIntent(null); 632 633 starter.setReason("testActivityStartsLogging_logsWhenEnabled").execute(); 634 635 // verify the above activity start was logged 636 verify(mActivityMetricsLogger, times(1)).logAbortedBgActivityStart(any(), any(), 637 eq(FAKE_CALLING_UID), eq(FAKE_CALLING_PACKAGE), anyInt(), anyBoolean(), 638 eq(FAKE_REAL_CALLING_UID), anyInt(), anyBoolean(), eq(false)); 639 } 640 641 /** 642 * This test ensures that unsupported usecases aren't aborted when background starts are 643 * allowed. 644 */ 645 @Test testBackgroundActivityStartsAllowed_noStartsAborted()646 public void testBackgroundActivityStartsAllowed_noStartsAborted() { 647 doReturn(true).when(mAtm).isBackgroundActivityStartsEnabled(); 648 runAndVerifyBackgroundActivityStartsSubtest("allowed_noStartsAborted", false, 649 UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP, 650 UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, 651 false, false, false, false, false, false, false, false); 652 } 653 654 /** 655 * This test ensures that unsupported usecases are aborted when background starts are 656 * disallowed. 657 */ 658 @Test testBackgroundActivityStartsDisallowed_unsupportedUsecaseAborted()659 public void testBackgroundActivityStartsDisallowed_unsupportedUsecaseAborted() { 660 doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled(); 661 runAndVerifyBackgroundActivityStartsSubtest( 662 "disallowed_unsupportedUsecase_aborted", true, 663 UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP, 664 UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, 665 false, false, false, false, false, false, false, false); 666 } 667 668 /** 669 * This test ensures that unsupported usecases are aborted when background starts are 670 * disallowed. 671 */ 672 @Test testBackgroundActivityStartsDisallowed_callingUidProcessStateTopAborted()673 public void testBackgroundActivityStartsDisallowed_callingUidProcessStateTopAborted() { 674 doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled(); 675 runAndVerifyBackgroundActivityStartsSubtest( 676 "disallowed_callingUidProcessStateTop_aborted", true, 677 UNIMPORTANT_UID, false, PROCESS_STATE_TOP, 678 UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, 679 false, false, false, false, false, false, false, false); 680 } 681 682 /** 683 * This test ensures that unsupported usecases are aborted when background starts are 684 * disallowed. 685 */ 686 @Test testBackgroundActivityStartsDisallowed_realCallingUidProcessStateTopAborted()687 public void testBackgroundActivityStartsDisallowed_realCallingUidProcessStateTopAborted() { 688 doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled(); 689 runAndVerifyBackgroundActivityStartsSubtest( 690 "disallowed_realCallingUidProcessStateTop_aborted", true, 691 UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP, 692 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP, 693 false, false, false, false, false, false, false, false); 694 } 695 696 /** 697 * This test ensures that unsupported usecases are aborted when background starts are 698 * disallowed. 699 */ 700 @Test testBackgroundActivityStartsDisallowed_hasForegroundActivitiesAborted()701 public void testBackgroundActivityStartsDisallowed_hasForegroundActivitiesAborted() { 702 doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled(); 703 runAndVerifyBackgroundActivityStartsSubtest( 704 "disallowed_hasForegroundActivities_aborted", true, 705 UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP, 706 UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, 707 true, false, false, false, false, false, false, false); 708 } 709 710 /** 711 * This test ensures that unsupported usecases are aborted when background starts are 712 * disallowed. 713 */ 714 @Test testBackgroundActivityStartsDisallowed_pinnedSingleInstanceAborted()715 public void testBackgroundActivityStartsDisallowed_pinnedSingleInstanceAborted() { 716 doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled(); 717 runAndVerifyBackgroundActivityStartsSubtest( 718 "disallowed_pinned_singleinstance_aborted", true, 719 UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP, 720 UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, 721 false, false, false, false, false, false, true, false); 722 } 723 724 /** 725 * This test ensures that supported usecases aren't aborted when background starts are 726 * disallowed. Each scenarios tests one condition that makes them supported in isolation. In 727 * this case the calling process runs as ROOT_UID. 728 */ 729 @Test testBackgroundActivityStartsDisallowed_rootUidNotAborted()730 public void testBackgroundActivityStartsDisallowed_rootUidNotAborted() { 731 doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled(); 732 runAndVerifyBackgroundActivityStartsSubtest("disallowed_rootUid_notAborted", false, 733 Process.ROOT_UID, false, PROCESS_STATE_BOUND_TOP, 734 UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, 735 false, false, false, false, false, false, false, false); 736 } 737 738 /** 739 * This test ensures that supported usecases aren't aborted when background starts are 740 * disallowed. Each scenarios tests one condition that makes them supported in isolation. In 741 * this case the calling process is running as SYSTEM_UID. 742 */ 743 @Test testBackgroundActivityStartsDisallowed_systemUidNotAborted()744 public void testBackgroundActivityStartsDisallowed_systemUidNotAborted() { 745 doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled(); 746 runAndVerifyBackgroundActivityStartsSubtest("disallowed_systemUid_notAborted", false, 747 Process.SYSTEM_UID, false, PROCESS_STATE_BOUND_TOP, 748 UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, 749 false, false, false, false, false, false, false, false); 750 } 751 752 /** 753 * This test ensures that supported usecases aren't aborted when background starts are 754 * disallowed. Each scenarios tests one condition that makes them supported in isolation. In 755 * this case the calling process is running as NFC_UID. 756 */ 757 @Test testBackgroundActivityStartsDisallowed_nfcUidNotAborted()758 public void testBackgroundActivityStartsDisallowed_nfcUidNotAborted() { 759 doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled(); 760 runAndVerifyBackgroundActivityStartsSubtest("disallowed_nfcUid_notAborted", false, 761 Process.NFC_UID, false, PROCESS_STATE_BOUND_TOP, 762 UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, 763 false, false, false, false, false, false, false, false); 764 } 765 766 /** 767 * This test ensures that supported usecases aren't aborted when background starts are 768 * disallowed. Each scenarios tests one condition that makes them supported in isolation. In 769 * this case the calling process has a visible window. 770 */ 771 @Test testBackgroundActivityStartsDisallowed_callingUidHasVisibleWindowNotAborted()772 public void testBackgroundActivityStartsDisallowed_callingUidHasVisibleWindowNotAborted() { 773 doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled(); 774 runAndVerifyBackgroundActivityStartsSubtest( 775 "disallowed_callingUidHasVisibleWindow_notAborted", false, 776 UNIMPORTANT_UID, true, PROCESS_STATE_BOUND_TOP, 777 UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, 778 false, false, false, false, false, false, false, false); 779 } 780 781 /** 782 * The sending app has a visible window, but does not (by default) allow the pending intent to 783 * start the background activity. 784 */ 785 @Test 786 @Ignore("b/266015587") testBackgroundActivityStartsDisallowed_realCallingUidHasVisibleWindowAborted()787 public void testBackgroundActivityStartsDisallowed_realCallingUidHasVisibleWindowAborted() { 788 doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled(); 789 790 runAndVerifyBackgroundActivityStartsSubtest( 791 "disallowed_realCallingUidHasVisibleWindow_abortedInU", true, 792 UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP, 793 UNIMPORTANT_UID2, true, PROCESS_STATE_BOUND_TOP, 794 false, false, false, false, false, false, false, false); 795 } 796 797 /** 798 * This test ensures that supported usecases aren't aborted when background starts are 799 * disallowed. Each scenarios tests one condition that makes them supported in isolation. In 800 * this case the caller is in the recent activity list. 801 */ 802 @Test testBackgroundActivityStartsDisallowed_callerIsRecentsNotAborted()803 public void testBackgroundActivityStartsDisallowed_callerIsRecentsNotAborted() { 804 doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled(); 805 runAndVerifyBackgroundActivityStartsSubtest( 806 "disallowed_callerIsRecents_notAborted", false, 807 UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP, 808 UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, 809 false, true, false, false, false, false, false, false); 810 } 811 812 /** 813 * This test ensures that supported usecases aren't aborted when background starts are 814 * disallowed. Each scenarios tests one condition that makes them supported in isolation. In 815 * this case the caller is temporarily (10s) allowed to start. 816 */ 817 @Test testBackgroundActivityStartsDisallowed_callerIsAllowedNotAborted()818 public void testBackgroundActivityStartsDisallowed_callerIsAllowedNotAborted() { 819 doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled(); 820 runAndVerifyBackgroundActivityStartsSubtest( 821 "disallowed_callerIsAllowed_notAborted", false, 822 UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP, 823 UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, 824 false, false, true, false, false, false, false, false); 825 } 826 827 /** 828 * This test ensures that supported usecases aren't aborted when background starts are 829 * disallowed. Each scenarios tests one condition that makes them supported in isolation. In 830 * this case the caller explicitly has background activity start privilege. 831 */ 832 @Test testBackgroundActivityStartsDisallowed_callerIsInstrumentingWithBASPnotAborted()833 public void testBackgroundActivityStartsDisallowed_callerIsInstrumentingWithBASPnotAborted() { 834 doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled(); 835 runAndVerifyBackgroundActivityStartsSubtest( 836 "disallowed_callerIsInstrumentingWithBackgroundActivityStartPrivileges_notAborted", 837 false, 838 UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP, 839 UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, 840 false, false, false, true, false, false, false, false); 841 } 842 843 /** 844 * This test ensures that supported usecases aren't aborted when background starts are 845 * disallowed. Each scenarios tests one condition that makes them supported in isolation. In 846 * this case the caller is a device owner. 847 */ 848 @Test 849 public void testBackgroundActivityStartsDisallowed_callingPackageNameIsDeviceOwnerNotAborted()850 testBackgroundActivityStartsDisallowed_callingPackageNameIsDeviceOwnerNotAborted() { 851 doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled(); 852 runAndVerifyBackgroundActivityStartsSubtest( 853 "disallowed_callingPackageNameIsDeviceOwner_notAborted", false, 854 UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP, 855 UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, 856 false, false, false, false, true, false, false, false); 857 } 858 859 /** 860 * This test ensures that supported usecases aren't aborted when background starts are 861 * disallowed. Each scenarios tests one condition that makes them supported in isolation. In 862 * this case the caller is a affiliated profile owner. 863 */ 864 @Test 865 public void testBackgroundActivityStartsDisallowed_isAffiliatedProfileOwnerNotAborted()866 testBackgroundActivityStartsDisallowed_isAffiliatedProfileOwnerNotAborted() { 867 doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled(); 868 runAndVerifyBackgroundActivityStartsSubtest( 869 "disallowed_callingUidIsAffiliatedProfileOwner_notAborted", false, 870 UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP, 871 UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, 872 false, false, false, false, false, true, false, false); 873 } 874 875 /** 876 * This test ensures that supported usecases aren't aborted when background starts are 877 * disallowed. Each scenarios tests one condition that makes them supported in isolation. In 878 * this case the caller has the OP_SYSTEM_EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION appop. 879 */ 880 @Test testBackgroundActivityStartsDisallowed_callerHasSystemExemptAppOpNotAborted()881 public void testBackgroundActivityStartsDisallowed_callerHasSystemExemptAppOpNotAborted() { 882 doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled(); 883 runAndVerifyBackgroundActivityStartsSubtest( 884 "disallowed_callerHasSystemExemptAppOpNotAborted", false, 885 UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP, 886 UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, 887 false, false, false, false, false, false, false, true); 888 } 889 890 /** 891 * This test ensures that supported usecases aren't aborted when background starts are 892 * disallowed. Each scenarios tests one condition that makes them supported in isolation. In 893 * this case the caller is an IME. 894 */ 895 @Test testBackgroundActivityStartsDisallowed_callingPackageNameIsImeNotAborted()896 public void testBackgroundActivityStartsDisallowed_callingPackageNameIsImeNotAborted() { 897 doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled(); 898 setupImeWindow(); 899 runAndVerifyBackgroundActivityStartsSubtest( 900 "disallowed_callingPackageNameIsIme_notAborted", false, 901 CURRENT_IME_UID, false, PROCESS_STATE_BOUND_TOP, 902 UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, 903 false, false, false, false, false, false, false, false); 904 } 905 906 /** 907 * This test ensures proper logging for BAL_ALLOW_PERMISSION. 908 */ 909 @Test testBackgroundActivityStartsAllowed_logging()910 public void testBackgroundActivityStartsAllowed_logging() { 911 doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled(); 912 MockitoSession mockingSession = mockitoSession() 913 .mockStatic(ActivityTaskManagerService.class) 914 .mockStatic(FrameworkStatsLog.class) 915 .strictness(Strictness.LENIENT) 916 .startMocking(); 917 doReturn(PERMISSION_GRANTED).when(() -> ActivityTaskManagerService.checkPermission( 918 eq(START_ACTIVITIES_FROM_BACKGROUND), 919 anyInt(), anyInt())); 920 runAndVerifyBackgroundActivityStartsSubtest( 921 "allowed_notAborted", false, 922 UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP, 923 UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, 924 false, true, false, false, false, false, false, false); 925 verify(() -> FrameworkStatsLog.write(FrameworkStatsLog.BAL_ALLOWED, 926 "", // activity name 927 BackgroundActivityStartController.BAL_ALLOW_PERMISSION, 928 UNIMPORTANT_UID, 929 UNIMPORTANT_UID2)); 930 mockingSession.finishMocking(); 931 } 932 933 /** 934 * This test ensures proper logging for BAL_ALLOW_PENDING_INTENT. 935 */ 936 @Test testBackgroundActivityStartsAllowed_loggingPendingIntentAllowed()937 public void testBackgroundActivityStartsAllowed_loggingPendingIntentAllowed() { 938 doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled(); 939 MockitoSession mockingSession = mockitoSession() 940 .mockStatic(ActivityTaskManagerService.class) 941 .mockStatic(FrameworkStatsLog.class) 942 .mockStatic(PendingIntentRecord.class) 943 .strictness(Strictness.LENIENT) 944 .startMocking(); 945 doReturn(PERMISSION_GRANTED).when(() -> ActivityTaskManagerService.checkPermission( 946 eq(START_ACTIVITIES_FROM_BACKGROUND), 947 anyInt(), anyInt())); 948 doReturn(BackgroundStartPrivileges.allowBackgroundActivityStarts(null)).when( 949 () -> PendingIntentRecord.getBackgroundStartPrivilegesAllowedByCaller( 950 anyObject(), anyInt(), anyObject())); 951 runAndVerifyBackgroundActivityStartsSubtest( 952 "allowed_notAborted", false, 953 UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP, 954 Process.SYSTEM_UID, true, PROCESS_STATE_BOUND_TOP, 955 false, true, false, false, false, false, false, false); 956 verify(() -> FrameworkStatsLog.write(FrameworkStatsLog.BAL_ALLOWED, 957 DEFAULT_COMPONENT_PACKAGE_NAME + "/" + DEFAULT_COMPONENT_PACKAGE_NAME, 958 BackgroundActivityStartController.BAL_ALLOW_PENDING_INTENT, 959 UNIMPORTANT_UID, 960 Process.SYSTEM_UID)); 961 mockingSession.finishMocking(); 962 } 963 964 965 @Test testBackgroundActivityStartsAllowed_sdkSandboxClientAppHasVisibleWindow()966 public void testBackgroundActivityStartsAllowed_sdkSandboxClientAppHasVisibleWindow() { 967 doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled(); 968 // The SDK's associated client app has a visible window 969 doReturn(true).when(mAtm).hasActiveVisibleWindow( 970 Process.getAppUidForSdkSandboxUid(SDK_SANDBOX_UID)); 971 runAndVerifyBackgroundActivityStartsSubtest( 972 "allowed_sdkSandboxClientAppHasVisibleWindow", false, SDK_SANDBOX_UID, 973 false, PROCESS_STATE_TOP, SDK_SANDBOX_UID, false, 974 PROCESS_STATE_TOP, true, false, false, 975 false, false, false, false, false); 976 } 977 978 @Test testBackgroundActivityStartsDisallowed_sdkSandboxClientHasNoVisibleWindow()979 public void testBackgroundActivityStartsDisallowed_sdkSandboxClientHasNoVisibleWindow() { 980 doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled(); 981 // The SDK's associated client app does not have a visible window 982 doReturn(false).when(mAtm).hasActiveVisibleWindow( 983 Process.getAppUidForSdkSandboxUid(SDK_SANDBOX_UID)); 984 runAndVerifyBackgroundActivityStartsSubtest( 985 "disallowed_sdkSandboxClientHasNoVisibleWindow", true, SDK_SANDBOX_UID, 986 false, PROCESS_STATE_TOP, SDK_SANDBOX_UID, false, 987 PROCESS_STATE_TOP, true, false, false, 988 false, false, false, false, false); 989 990 } 991 992 @Test testBackgroundActivityStartsAllowed_sdkSandboxMultiUserClientHasVisibleWindow()993 public void testBackgroundActivityStartsAllowed_sdkSandboxMultiUserClientHasVisibleWindow() { 994 doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled(); 995 // The SDK's associated client app has a visible window 996 doReturn(true).when(mAtm).hasActiveVisibleWindow( 997 Process.getAppUidForSdkSandboxUid(SECONDARY_USER_SDK_SANDBOX_UID)); 998 runAndVerifyBackgroundActivityStartsSubtest( 999 "allowed_sdkSandboxMultiUserClientHasVisibleWindow", false, 1000 SECONDARY_USER_SDK_SANDBOX_UID, false, PROCESS_STATE_TOP, 1001 SECONDARY_USER_SDK_SANDBOX_UID, false, PROCESS_STATE_TOP, 1002 false, false, false, false, 1003 false, false, false, false); 1004 } 1005 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)1006 private void runAndVerifyBackgroundActivityStartsSubtest(String name, boolean shouldHaveAborted, 1007 int callingUid, boolean callingUidHasVisibleWindow, int callingUidProcState, 1008 int realCallingUid, boolean realCallingUidHasVisibleWindow, int realCallingUidProcState, 1009 boolean hasForegroundActivities, boolean callerIsRecents, 1010 boolean callerIsTempAllowed, 1011 boolean callerIsInstrumentingWithBackgroundActivityStartPrivileges, 1012 boolean isCallingUidDeviceOwner, 1013 boolean isCallingUidAffiliatedProfileOwner, 1014 boolean isPinnedSingleInstance, 1015 boolean hasSystemExemptAppOp) { 1016 // window visibility 1017 doReturn(callingUidHasVisibleWindow).when(mAtm).hasActiveVisibleWindow(callingUid); 1018 doReturn(realCallingUidHasVisibleWindow).when(mAtm).hasActiveVisibleWindow(realCallingUid); 1019 // process importance 1020 mAtm.mActiveUids.onUidActive(callingUid, callingUidProcState); 1021 mAtm.mActiveUids.onUidActive(realCallingUid, realCallingUidProcState); 1022 // foreground activities 1023 final IApplicationThread caller = mock(IApplicationThread.class); 1024 final WindowProcessListener listener = mock(WindowProcessListener.class); 1025 final ApplicationInfo ai = new ApplicationInfo(); 1026 ai.uid = callingUid; 1027 ai.packageName = "com.android.test.package"; 1028 final WindowProcessController callerApp = 1029 spy(new WindowProcessController(mAtm, ai, null, callingUid, -1, null, listener)); 1030 doReturn(hasForegroundActivities).when(callerApp).hasForegroundActivities(); 1031 doReturn(callerApp).when(mAtm).getProcessController(caller); 1032 // caller is recents 1033 RecentTasks recentTasks = mock(RecentTasks.class); 1034 mAtm.mTaskSupervisor.setRecentTasks(recentTasks); 1035 doReturn(callerIsRecents).when(recentTasks).isCallerRecents(callingUid); 1036 // caller is temp allowed 1037 if (callerIsTempAllowed) { 1038 callerApp.addOrUpdateBackgroundStartPrivileges(new Binder(), 1039 BackgroundStartPrivileges.ALLOW_BAL); 1040 } 1041 // caller is instrumenting with background activity starts privileges 1042 callerApp.setInstrumenting(callerIsInstrumentingWithBackgroundActivityStartPrivileges, 1043 callerIsInstrumentingWithBackgroundActivityStartPrivileges ? Process.SHELL_UID : -1, 1044 callerIsInstrumentingWithBackgroundActivityStartPrivileges); 1045 // callingUid is the device owner 1046 doReturn(isCallingUidDeviceOwner).when(mAtm).isDeviceOwner(callingUid); 1047 // callingUid is the affiliated profile owner 1048 doReturn(isCallingUidAffiliatedProfileOwner).when(mAtm) 1049 .isAffiliatedProfileOwner(callingUid); 1050 1051 // caller has OP_SYSTEM_EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION appop 1052 doReturn(hasSystemExemptAppOp ? AppOpsManager.MODE_ALLOWED 1053 : AppOpsManager.MODE_DEFAULT).when(mAppOpsManager).checkOpNoThrow( 1054 eq(AppOpsManager.OP_SYSTEM_EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION), 1055 anyInt(), any()); 1056 1057 int launchMode = LAUNCH_MULTIPLE; 1058 if (isPinnedSingleInstance) { 1059 final ActivityRecord baseActivity = 1060 new ActivityBuilder(mAtm).setCreateTask(true).build(); 1061 baseActivity.getRootTask() 1062 .setWindowingMode(WINDOWING_MODE_PINNED); 1063 doReturn(baseActivity).when(mRootWindowContainer).findTask(any(), any()); 1064 launchMode = LAUNCH_SINGLE_INSTANCE; 1065 } 1066 1067 final ActivityOptions options = spy(ActivityOptions.makeBasic()); 1068 ActivityRecord[] outActivity = new ActivityRecord[1]; 1069 ActivityStarter starter = prepareStarter( 1070 FLAG_ACTIVITY_NEW_TASK, true, launchMode) 1071 .setCallingPackage("com.whatever.dude") 1072 .setCaller(caller) 1073 .setCallingUid(callingUid) 1074 .setRealCallingUid(realCallingUid) 1075 .setActivityOptions(new SafeActivityOptions(options)) 1076 .setOutActivity(outActivity); 1077 1078 final int result = starter.setReason("testBackgroundActivityStarts_" + name).execute(); 1079 1080 assertEquals(ActivityStarter.getExternalResult( 1081 shouldHaveAborted ? START_ABORTED : START_SUCCESS), result); 1082 verify(options, times(shouldHaveAborted ? 1 : 0)).abort(); 1083 1084 final ActivityRecord startedActivity = outActivity[0]; 1085 if (startedActivity != null && startedActivity.getTask() != null) { 1086 // Remove the activity so it doesn't interfere with with subsequent activity launch 1087 // tests from this method. 1088 startedActivity.getTask().removeChild(startedActivity); 1089 } 1090 } 1091 1092 /** 1093 * This test ensures that {@link ActivityStarter#setTargetRootTaskIfNeeded} will task the 1094 * adjacent task of indicated launch target into account. So the existing task will be launched 1095 * into closer target. 1096 */ 1097 @Test testAdjustLaunchTargetWithAdjacentTask()1098 public void testAdjustLaunchTargetWithAdjacentTask() { 1099 // Create adjacent tasks and put one activity under it 1100 final Task parent = new TaskBuilder(mSupervisor).build(); 1101 final Task adjacentParent = new TaskBuilder(mSupervisor).build(); 1102 parent.setAdjacentTaskFragment(adjacentParent); 1103 final ActivityRecord activity = new ActivityBuilder(mAtm) 1104 .setParentTask(parent) 1105 .setCreateTask(true).build(); 1106 1107 // Launch the activity to its adjacent parent 1108 final ActivityOptions options = ActivityOptions.makeBasic() 1109 .setLaunchRootTask(adjacentParent.mRemoteToken.toWindowContainerToken()); 1110 prepareStarter(FLAG_ACTIVITY_NEW_TASK, false /* mockGetRootTask */) 1111 .setReason("testAdjustLaunchTargetWithAdjacentTask") 1112 .setIntent(activity.intent) 1113 .setActivityOptions(options.toBundle()) 1114 .execute(); 1115 1116 // Verify the activity will be launched into the original parent 1117 assertTrue(activity.isDescendantOf(parent)); 1118 } 1119 1120 /** 1121 * This test ensures that {@link ActivityStarter#setTargetRootTaskIfNeeded} will 1122 * move the existing task to front if the current focused root task doesn't have running task. 1123 */ 1124 @Test testBringTaskToFrontWhenFocusedTaskIsFinishing()1125 public void testBringTaskToFrontWhenFocusedTaskIsFinishing() { 1126 // Put 2 tasks in the same root task (simulate the behavior of home root task). 1127 final Task rootTask = new TaskBuilder(mSupervisor).build(); 1128 final ActivityRecord activity = new ActivityBuilder(mAtm) 1129 .setParentTask(rootTask) 1130 .setCreateTask(true).build(); 1131 new ActivityBuilder(mAtm) 1132 .setParentTask(activity.getRootTask()) 1133 .setCreateTask(true).build(); 1134 1135 // Create a top finishing activity. 1136 final ActivityRecord finishingTopActivity = new ActivityBuilder(mAtm) 1137 .setCreateTask(true).build(); 1138 finishingTopActivity.getRootTask().moveToFront("finishingTopActivity"); 1139 1140 assertEquals(finishingTopActivity, mRootWindowContainer.topRunningActivity()); 1141 finishingTopActivity.finishing = true; 1142 1143 // Launch the bottom task of the target root task. 1144 prepareStarter(FLAG_ACTIVITY_NEW_TASK, false /* mockGetRootTask */) 1145 .setReason("testBringTaskToFrontWhenFocusedTaskIsFinishing") 1146 .setIntent(activity.intent.addFlags( 1147 FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK)) 1148 .execute(); 1149 verify(activity.getRootTask()).startActivityLocked(any(), any(), anyBoolean(), 1150 eq(true) /* isTaskSwitch */, any(), any()); 1151 // The hierarchies of the activity should move to front. 1152 assertEquals(activity.getTask(), mRootWindowContainer.topRunningActivity().getTask()); 1153 } 1154 1155 /** 1156 * This test ensures that when starting an existing single task activity on secondary display 1157 * which is not the top focused display, it should deliver new intent to the activity and not 1158 * create a new stack. 1159 */ 1160 @Test testDeliverIntentToTopActivityOfNonTopDisplay()1161 public void testDeliverIntentToTopActivityOfNonTopDisplay() { 1162 final ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK, 1163 false /* mockGetRootTask */); 1164 1165 // Create a secondary display at bottom. 1166 final TestDisplayContent secondaryDisplay = 1167 new TestDisplayContent.Builder(mAtm, 1000, 1500) 1168 .setPosition(POSITION_BOTTOM).build(); 1169 final TaskDisplayArea secondaryTaskContainer = secondaryDisplay.getDefaultTaskDisplayArea(); 1170 final Task stack = secondaryTaskContainer.createRootTask( 1171 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); 1172 1173 // Create an activity record on the top of secondary display. 1174 final ActivityRecord topActivityOnSecondaryDisplay = createSingleTaskActivityOn(stack); 1175 1176 // Put an activity on default display as the top focused activity. 1177 new ActivityBuilder(mAtm).setCreateTask(true).build(); 1178 1179 // Start activity with the same intent as {@code topActivityOnSecondaryDisplay} 1180 // on secondary display. 1181 final ActivityOptions options = ActivityOptions.makeBasic() 1182 .setLaunchDisplayId(secondaryDisplay.mDisplayId); 1183 final int result = starter.setReason("testDeliverIntentToTopActivityOfNonTopDisplay") 1184 .setIntent(topActivityOnSecondaryDisplay.intent) 1185 .setActivityOptions(options.toBundle()) 1186 .execute(); 1187 1188 // Ensure result is delivering intent to top. 1189 assertEquals(START_DELIVERED_TO_TOP, result); 1190 1191 // Ensure secondary display only creates one stack. 1192 verify(secondaryTaskContainer, times(1)).createRootTask(anyInt(), anyInt(), anyBoolean()); 1193 } 1194 1195 /** 1196 * This test ensures that when starting an existing non-top single task activity on secondary 1197 * display which is the top focused display, it should bring the task to front without creating 1198 * unused stack. 1199 */ 1200 @Test testBringTaskToFrontOnSecondaryDisplay()1201 public void testBringTaskToFrontOnSecondaryDisplay() { 1202 final ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK, 1203 false /* mockGetRootTask */); 1204 1205 // Create a secondary display with an activity. 1206 final TestDisplayContent secondaryDisplay = 1207 new TestDisplayContent.Builder(mAtm, 1000, 1500).build(); 1208 mRootWindowContainer.positionChildAt(POSITION_TOP, secondaryDisplay, 1209 false /* includingParents */); 1210 final TaskDisplayArea secondaryTaskContainer = secondaryDisplay.getDefaultTaskDisplayArea(); 1211 final ActivityRecord singleTaskActivity = createSingleTaskActivityOn( 1212 secondaryTaskContainer.createRootTask(WINDOWING_MODE_FULLSCREEN, 1213 ACTIVITY_TYPE_STANDARD, false /* onTop */)); 1214 // Activity should start invisible since we are bringing it to front. 1215 singleTaskActivity.setVisible(false); 1216 singleTaskActivity.setVisibleRequested(false); 1217 1218 // Create another activity on top of the secondary display. 1219 final Task topStack = secondaryTaskContainer.createRootTask(WINDOWING_MODE_FULLSCREEN, 1220 ACTIVITY_TYPE_STANDARD, true /* onTop */); 1221 final Task topTask = new TaskBuilder(mSupervisor).setParentTask(topStack).build(); 1222 new ActivityBuilder(mAtm).setTask(topTask).build(); 1223 1224 doReturn(mActivityMetricsLogger).when(mSupervisor).getActivityMetricsLogger(); 1225 // Start activity with the same intent as {@code singleTaskActivity} on secondary display. 1226 final ActivityOptions options = ActivityOptions.makeBasic() 1227 .setLaunchDisplayId(secondaryDisplay.mDisplayId); 1228 final int result = starter.setReason("testBringTaskToFrontOnSecondaryDisplay") 1229 .setIntent(singleTaskActivity.intent) 1230 .setActivityOptions(options.toBundle()) 1231 .execute(); 1232 1233 // Ensure result is moving existing task to front. 1234 assertEquals(START_TASK_TO_FRONT, result); 1235 1236 // Ensure secondary display only creates two stacks. 1237 verify(secondaryTaskContainer, times(2)).createRootTask(anyInt(), anyInt(), anyBoolean()); 1238 // The metrics logger should receive the same result and non-null options. 1239 verify(mActivityMetricsLogger).notifyActivityLaunched(any() /* launchingState */, 1240 eq(result), eq(false) /* newActivityCreated */, eq(singleTaskActivity), 1241 notNull() /* options */); 1242 } 1243 1244 @Test testWasVisibleInRestartAttempt()1245 public void testWasVisibleInRestartAttempt() { 1246 final ActivityStarter starter = prepareStarter( 1247 FLAG_ACTIVITY_RESET_TASK_IF_NEEDED | FLAG_ACTIVITY_SINGLE_TOP, false); 1248 final ActivityRecord reusableActivity = 1249 new ActivityBuilder(mAtm).setCreateTask(true).build(); 1250 final ActivityRecord topActivity = 1251 new ActivityBuilder(mAtm).setCreateTask(true).build(); 1252 1253 // Make sure topActivity is on top 1254 topActivity.getRootTask().moveToFront("testWasVisibleInRestartAttempt"); 1255 reusableActivity.setVisible(false); 1256 1257 final TaskChangeNotificationController taskChangeNotifier = 1258 mAtm.getTaskChangeNotificationController(); 1259 spyOn(taskChangeNotifier); 1260 1261 Task task = topActivity.getTask(); 1262 starter.postStartActivityProcessing( 1263 task.getTopNonFinishingActivity(), START_DELIVERED_TO_TOP, task.getRootTask()); 1264 1265 verify(taskChangeNotifier).notifyActivityRestartAttempt( 1266 any(), anyBoolean(), anyBoolean(), anyBoolean()); 1267 verify(taskChangeNotifier).notifyActivityRestartAttempt( 1268 any(), anyBoolean(), anyBoolean(), eq(true)); 1269 1270 Task task2 = reusableActivity.getTask(); 1271 starter.postStartActivityProcessing( 1272 task2.getTopNonFinishingActivity(), START_TASK_TO_FRONT, task.getRootTask()); 1273 verify(taskChangeNotifier, times(2)).notifyActivityRestartAttempt( 1274 any(), anyBoolean(), anyBoolean(), anyBoolean()); 1275 verify(taskChangeNotifier).notifyActivityRestartAttempt( 1276 any(), anyBoolean(), anyBoolean(), eq(false)); 1277 } 1278 createSingleTaskActivityOn(Task task)1279 private ActivityRecord createSingleTaskActivityOn(Task task) { 1280 final ComponentName componentName = ComponentName.createRelative( 1281 DEFAULT_COMPONENT_PACKAGE_NAME, 1282 DEFAULT_COMPONENT_PACKAGE_NAME + ".SingleTaskActivity"); 1283 return new ActivityBuilder(mAtm) 1284 .setComponent(componentName) 1285 .setLaunchMode(LAUNCH_SINGLE_TASK) 1286 .setTask(task) 1287 .build(); 1288 } 1289 1290 /** 1291 * This test ensures that a reused top activity in the top focused stack is able to be 1292 * reparented to another display. 1293 */ 1294 @Test testReparentTopFocusedActivityToSecondaryDisplay()1295 public void testReparentTopFocusedActivityToSecondaryDisplay() { 1296 final ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK, 1297 false /* mockGetRootTask */); 1298 1299 // Create a secondary display at bottom. 1300 final TestDisplayContent secondaryDisplay = addNewDisplayContentAt(POSITION_BOTTOM); 1301 final TaskDisplayArea secondaryTaskContainer = secondaryDisplay.getDefaultTaskDisplayArea(); 1302 secondaryTaskContainer.createRootTask(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, 1303 true /* onTop */); 1304 1305 // Put an activity on default display as the top focused activity. 1306 final ActivityRecord topActivity = new ActivityBuilder(mAtm) 1307 .setCreateTask(true) 1308 .setLaunchMode(LAUNCH_SINGLE_TASK) 1309 .build(); 1310 1311 // Start activity with the same intent as {@code topActivity} on secondary display. 1312 final ActivityOptions options = ActivityOptions.makeBasic() 1313 .setLaunchDisplayId(secondaryDisplay.mDisplayId); 1314 starter.setReason("testReparentTopFocusedActivityToSecondaryDisplay") 1315 .setIntent(topActivity.intent) 1316 .setActivityOptions(options.toBundle()) 1317 .execute(); 1318 1319 // Ensure the activity is moved to secondary display. 1320 assertEquals(secondaryDisplay, topActivity.mDisplayContent); 1321 } 1322 1323 /** 1324 * This test ensures that starting an activity with the freeze-task-list activity option will 1325 * actually freeze the task list 1326 */ 1327 @Test testFreezeTaskListActivityOption()1328 public void testFreezeTaskListActivityOption() { 1329 RecentTasks recentTasks = mock(RecentTasks.class); 1330 mAtm.mTaskSupervisor.setRecentTasks(recentTasks); 1331 doReturn(true).when(recentTasks).isCallerRecents(anyInt()); 1332 1333 final ActivityStarter starter = prepareStarter(0 /* flags */); 1334 final ActivityOptions options = ActivityOptions.makeBasic(); 1335 options.setFreezeRecentTasksReordering(); 1336 1337 starter.setReason("testFreezeTaskListActivityOption") 1338 .setActivityOptions(new SafeActivityOptions(options)) 1339 .execute(); 1340 1341 verify(recentTasks, times(1)).setFreezeTaskListReordering(); 1342 verify(recentTasks, times(0)).resetFreezeTaskListReorderingOnTimeout(); 1343 } 1344 1345 /** 1346 * This test ensures that if we froze the task list as a part of starting an activity that fails 1347 * to start, that we also reset the task list. 1348 */ 1349 @Test testFreezeTaskListActivityOptionFailedStart_expectResetFreezeTaskList()1350 public void testFreezeTaskListActivityOptionFailedStart_expectResetFreezeTaskList() { 1351 RecentTasks recentTasks = mock(RecentTasks.class); 1352 mAtm.mTaskSupervisor.setRecentTasks(recentTasks); 1353 doReturn(true).when(recentTasks).isCallerRecents(anyInt()); 1354 1355 final ActivityStarter starter = prepareStarter(0 /* flags */); 1356 final ActivityOptions options = ActivityOptions.makeBasic(); 1357 options.setFreezeRecentTasksReordering(); 1358 1359 starter.setReason("testFreezeTaskListActivityOptionFailedStart") 1360 .setActivityOptions(new SafeActivityOptions(options)) 1361 .execute(); 1362 1363 // Simulate a failed start 1364 starter.postStartActivityProcessing(null, START_CANCELED, null); 1365 1366 verify(recentTasks, times(1)).setFreezeTaskListReordering(); 1367 verify(recentTasks, times(1)).resetFreezeTaskListReorderingOnTimeout(); 1368 } 1369 1370 @Test testNoActivityInfo()1371 public void testNoActivityInfo() { 1372 final ActivityStarter starter = prepareStarter(0 /* flags */); 1373 spyOn(starter.mRequest); 1374 1375 final Intent intent = new Intent(); 1376 intent.setComponent(ActivityBuilder.getDefaultComponent()); 1377 starter.setReason("testNoActivityInfo").setIntent(intent) 1378 .setActivityInfo(null).execute(); 1379 verify(starter.mRequest).resolveActivity(any()); 1380 } 1381 1382 @Test testResolveEphemeralInstaller()1383 public void testResolveEphemeralInstaller() { 1384 final ActivityStarter starter = prepareStarter(0 /* flags */); 1385 final Intent intent = new Intent(); 1386 intent.setComponent(ActivityBuilder.getDefaultComponent()); 1387 1388 doReturn(true).when(mMockPackageManager).isInstantAppInstallerComponent(any()); 1389 starter.setIntent(intent).mRequest.resolveActivity(mAtm.mTaskSupervisor); 1390 1391 // Make sure the client intent won't be modified. 1392 assertThat(intent.getComponent()).isNotNull(); 1393 assertThat(starter.getIntent().getComponent()).isNull(); 1394 } 1395 1396 @Test testNotAllowIntentWithFd()1397 public void testNotAllowIntentWithFd() { 1398 final ActivityStarter starter = prepareStarter(0 /* flags */); 1399 final Intent intent = spy(new Intent()); 1400 intent.setComponent(ActivityBuilder.getDefaultComponent()); 1401 doReturn(true).when(intent).hasFileDescriptors(); 1402 1403 boolean exceptionCaught = false; 1404 try { 1405 starter.setIntent(intent).execute(); 1406 } catch (IllegalArgumentException ex) { 1407 exceptionCaught = true; 1408 } 1409 assertThat(exceptionCaught).isTrue(); 1410 } 1411 1412 @Test testRecycleTaskFromAnotherUser()1413 public void testRecycleTaskFromAnotherUser() { 1414 final ActivityStarter starter = prepareStarter(0 /* flags */); 1415 starter.mStartActivity = new ActivityBuilder(mAtm).build(); 1416 final Task task = new TaskBuilder(mAtm.mTaskSupervisor) 1417 .setParentTask(createTask(mDisplayContent, WINDOWING_MODE_FULLSCREEN, 1418 ACTIVITY_TYPE_STANDARD)) 1419 .setUserId(10) 1420 .build(); 1421 1422 final int result = starter.recycleTask(task, null, null, null); 1423 assertThat(result == START_SUCCESS).isTrue(); 1424 assertThat(starter.mAddingToTask).isTrue(); 1425 } 1426 1427 @Test testRecycleTaskWakeUpWhenDreaming()1428 public void testRecycleTaskWakeUpWhenDreaming() { 1429 doNothing().when(mWm.mAtmService.mTaskSupervisor).wakeUp(anyString()); 1430 doReturn(true).when(mWm.mAtmService).isDreaming(); 1431 final ActivityStarter starter = prepareStarter(0 /* flags */); 1432 final ActivityRecord target = new ActivityBuilder(mAtm).setCreateTask(true).build(); 1433 starter.mStartActivity = target; 1434 target.setVisibleRequested(false); 1435 target.setTurnScreenOn(true); 1436 // Assume the flag was consumed by relayout. 1437 target.setCurrentLaunchCanTurnScreenOn(false); 1438 startActivityInner(starter, target, null /* source */, null /* options */, 1439 null /* inTask */, null /* inTaskFragment */); 1440 // The flag should be set again when resuming (from recycleTask) the target as top. 1441 assertTrue(target.currentLaunchCanTurnScreenOn()); 1442 // In real case, dream activity has a higher priority (TaskDisplayArea#getPriority) that 1443 // will be put at a higher z-order. So it relies on wakeUp() to be dismissed. 1444 verify(mWm.mAtmService.mTaskSupervisor).wakeUp(anyString()); 1445 } 1446 1447 @Test testTargetTaskInSplitScreen()1448 public void testTargetTaskInSplitScreen() { 1449 final ActivityStarter starter = 1450 prepareStarter(FLAG_ACTIVITY_LAUNCH_ADJACENT, false /* mockGetRootTask */); 1451 final ActivityRecord top = new ActivityBuilder(mAtm).setCreateTask(true).build(); 1452 final ActivityOptions options = ActivityOptions.makeBasic(); 1453 final ActivityRecord[] outActivity = new ActivityRecord[1]; 1454 1455 // Activity must not land on split-screen task if currently not in split-screen mode. 1456 starter.setActivityOptions(options.toBundle()) 1457 .setReason("testTargetTaskInSplitScreen") 1458 .setOutActivity(outActivity).execute(); 1459 assertThat(outActivity[0].inMultiWindowMode()).isFalse(); 1460 1461 // Move activity to split-screen-primary task and make sure it has the focus. 1462 TestSplitOrganizer splitOrg = new TestSplitOrganizer(mAtm, top.getDisplayContent()); 1463 top.getRootTask().reparent(splitOrg.mPrimary, POSITION_BOTTOM); 1464 top.getRootTask().moveToFront("testTargetTaskInSplitScreen"); 1465 1466 // Activity must land on split-screen-secondary when launch adjacent. 1467 startActivityInner(starter, outActivity[0], top, options, null /* inTask */, 1468 null /* taskFragment*/); 1469 assertThat(outActivity[0].inMultiWindowMode()).isTrue(); 1470 } 1471 1472 @Test testActivityStart_expectAddedToRecentTask()1473 public void testActivityStart_expectAddedToRecentTask() { 1474 RecentTasks recentTasks = mock(RecentTasks.class); 1475 mAtm.mTaskSupervisor.setRecentTasks(recentTasks); 1476 doReturn(true).when(recentTasks).isCallerRecents(anyInt()); 1477 1478 final ActivityStarter starter = prepareStarter(0 /* flags */); 1479 1480 starter.setReason("testAddToTaskListOnActivityStart") 1481 .execute(); 1482 1483 verify(recentTasks, times(1)).add(any()); 1484 } 1485 1486 @Test testStartActivityInner_inTaskFragment_failsByDefault()1487 public void testStartActivityInner_inTaskFragment_failsByDefault() { 1488 final ActivityStarter starter = prepareStarter(0, false); 1489 final ActivityRecord targetRecord = new ActivityBuilder(mAtm).build(); 1490 final ActivityRecord sourceRecord = new ActivityBuilder(mAtm).setCreateTask(true).build(); 1491 final TaskFragment taskFragment = new TaskFragment(mAtm, sourceRecord.token, 1492 true /* createdByOrganizer */); 1493 sourceRecord.getTask().addChild(taskFragment, POSITION_TOP); 1494 1495 startActivityInner(starter, targetRecord, sourceRecord, null /* options */, 1496 null /* inTask */, taskFragment); 1497 1498 assertFalse(taskFragment.hasChild()); 1499 assertNotNull("Target record must be started on Task.", targetRecord.getParent().asTask()); 1500 } 1501 1502 @Test testStartActivityInner_inTaskFragment_allowedForSystemUid()1503 public void testStartActivityInner_inTaskFragment_allowedForSystemUid() { 1504 final ActivityStarter starter = prepareStarter(0, false); 1505 final ActivityRecord targetRecord = new ActivityBuilder(mAtm).build(); 1506 final ActivityRecord sourceRecord = new ActivityBuilder(mAtm).setCreateTask(true).build(); 1507 final TaskFragment taskFragment = new TaskFragment(mAtm, sourceRecord.token, 1508 true /* createdByOrganizer */); 1509 sourceRecord.getTask().addChild(taskFragment, POSITION_TOP); 1510 1511 taskFragment.setTaskFragmentOrganizer(mock(TaskFragmentOrganizerToken.class), SYSTEM_UID, 1512 "system_uid"); 1513 1514 startActivityInner(starter, targetRecord, sourceRecord, null /* options */, 1515 null /* inTask */, taskFragment); 1516 1517 assertTrue(taskFragment.hasChild()); 1518 } 1519 1520 @Test testStartActivityInner_inTaskFragment_allowedForSameUid()1521 public void testStartActivityInner_inTaskFragment_allowedForSameUid() { 1522 final ActivityStarter starter = prepareStarter(0, false); 1523 final ActivityRecord targetRecord = new ActivityBuilder(mAtm).build(); 1524 final ActivityRecord sourceRecord = new ActivityBuilder(mAtm).setCreateTask(true).build(); 1525 final TaskFragment taskFragment = new TaskFragment(mAtm, sourceRecord.token, 1526 true /* createdByOrganizer */); 1527 sourceRecord.getTask().addChild(taskFragment, POSITION_TOP); 1528 1529 taskFragment.setTaskFragmentOrganizer(mock(TaskFragmentOrganizerToken.class), 1530 targetRecord.getUid(), "test_process_name"); 1531 1532 startActivityInner(starter, targetRecord, sourceRecord, null /* options */, 1533 null /* inTask */, taskFragment); 1534 1535 assertTrue(taskFragment.hasChild()); 1536 } 1537 1538 @Test testStartActivityInner_inTaskFragment_allowedTrustedCertUid()1539 public void testStartActivityInner_inTaskFragment_allowedTrustedCertUid() { 1540 final ActivityStarter starter = prepareStarter(0, false); 1541 final ActivityRecord targetRecord = new ActivityBuilder(mAtm).build(); 1542 final ActivityRecord sourceRecord = new ActivityBuilder(mAtm).setCreateTask(true).build(); 1543 final TaskFragment taskFragment = new TaskFragment(mAtm, sourceRecord.token, 1544 true /* createdByOrganizer */); 1545 sourceRecord.getTask().addChild(taskFragment, POSITION_TOP); 1546 1547 taskFragment.setTaskFragmentOrganizer(mock(TaskFragmentOrganizerToken.class), 1548 12345, "test_process_name"); 1549 AndroidPackage androidPackage = mock(AndroidPackage.class); 1550 doReturn(androidPackage).when(mMockPackageManager).getPackage(eq(12345)); 1551 1552 Set<String> certs = new HashSet(Arrays.asList("test_cert1", "test_cert1")); 1553 targetRecord.info.setKnownActivityEmbeddingCerts(certs); 1554 SigningDetails signingDetails = mock(SigningDetails.class); 1555 doReturn(true).when(signingDetails).hasAncestorOrSelfWithDigest(any()); 1556 doReturn(signingDetails).when(androidPackage).getSigningDetails(); 1557 1558 startActivityInner(starter, targetRecord, sourceRecord, null /* options */, 1559 null /* inTask */, taskFragment); 1560 1561 assertTrue(taskFragment.hasChild()); 1562 } 1563 1564 @Test testStartActivityInner_inTaskFragment_allowedForUntrustedEmbedding()1565 public void testStartActivityInner_inTaskFragment_allowedForUntrustedEmbedding() { 1566 final ActivityStarter starter = prepareStarter(0, false); 1567 final ActivityRecord targetRecord = new ActivityBuilder(mAtm).build(); 1568 final ActivityRecord sourceRecord = new ActivityBuilder(mAtm).setCreateTask(true).build(); 1569 final TaskFragment taskFragment = new TaskFragment(mAtm, sourceRecord.token, 1570 true /* createdByOrganizer */); 1571 sourceRecord.getTask().addChild(taskFragment, POSITION_TOP); 1572 1573 targetRecord.info.flags |= ActivityInfo.FLAG_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING; 1574 1575 startActivityInner(starter, targetRecord, sourceRecord, null /* options */, 1576 null /* inTask */, taskFragment); 1577 1578 assertTrue(taskFragment.hasChild()); 1579 } 1580 1581 @Test testStartActivityInner_inTask()1582 public void testStartActivityInner_inTask() { 1583 final ActivityStarter starter = prepareStarter(0, false); 1584 // Simulate an app uses AppTask to create a non-attached task, and then it requests to 1585 // start activity in the task. 1586 final Task inTask = new TaskBuilder(mSupervisor).setTaskDisplayArea(null).setTaskId(123) 1587 .build(); 1588 inTask.inRecents = true; 1589 assertFalse(inTask.isAttached()); 1590 final ActivityRecord target = new ActivityBuilder(mAtm).build(); 1591 startActivityInner(starter, target, null /* source */, null /* options */, inTask, 1592 null /* inTaskFragment */); 1593 1594 assertTrue(inTask.isAttached()); 1595 assertEquals(inTask, target.getTask()); 1596 } 1597 1598 @Test testLaunchCookie_newAndExistingTask()1599 public void testLaunchCookie_newAndExistingTask() { 1600 final ActivityStarter starter = prepareStarter(0, false); 1601 1602 // Put an activity on default display as the top focused activity. 1603 ActivityRecord r = new ActivityBuilder(mAtm).setCreateTask(true).build(); 1604 1605 // Start an activity with a launch cookie 1606 final Binder cookie = new Binder(); 1607 final ActivityOptions options = ActivityOptions.makeBasic(); 1608 options.setLaunchCookie(cookie); 1609 final Intent intent = new Intent(); 1610 intent.setComponent(ActivityBuilder.getDefaultComponent()); 1611 starter.setReason("testLaunchCookie_newTask") 1612 .setIntent(intent) 1613 .setActivityOptions(options.toBundle()) 1614 .execute(); 1615 1616 // Verify the cookie is set 1617 assertTrue(mRootWindowContainer.topRunningActivity().mLaunchCookie == cookie); 1618 1619 // Relaunch the activity to bring the task forward 1620 final Binder newCookie = new Binder(); 1621 final ActivityOptions newOptions = ActivityOptions.makeBasic(); 1622 newOptions.setLaunchCookie(newCookie); 1623 starter.setReason("testLaunchCookie_existingTask") 1624 .setIntent(intent) 1625 .setActivityOptions(newOptions.toBundle()) 1626 .execute(); 1627 1628 // Verify the cookie is updated 1629 assertTrue(mRootWindowContainer.topRunningActivity().mLaunchCookie == newCookie); 1630 } 1631 1632 @Test testRemoteAnimation_appliesToExistingTask()1633 public void testRemoteAnimation_appliesToExistingTask() { 1634 final ActivityStarter starter = prepareStarter(0, false); 1635 1636 // Put an activity on default display as the top focused activity. 1637 ActivityRecord r = new ActivityBuilder(mAtm).setCreateTask(true).build(); 1638 final Intent intent = new Intent(); 1639 intent.setComponent(ActivityBuilder.getDefaultComponent()); 1640 starter.setReason("testRemoteAnimation_newTask") 1641 .setIntent(intent) 1642 .execute(); 1643 1644 assertNull(mRootWindowContainer.topRunningActivity().mPendingRemoteAnimation); 1645 1646 // Relaunch the activity with remote animation indicated in options. 1647 final RemoteAnimationAdapter adaptor = mock(RemoteAnimationAdapter.class); 1648 final ActivityOptions options = ActivityOptions.makeRemoteAnimation(adaptor); 1649 starter.setReason("testRemoteAnimation_existingTask") 1650 .setIntent(intent) 1651 .setActivityOptions(options.toBundle()) 1652 .execute(); 1653 1654 // Verify the remote animation is updated. 1655 assertEquals(adaptor, mRootWindowContainer.topRunningActivity().mPendingRemoteAnimation); 1656 } 1657 1658 @Test testStartLaunchIntoPipActivity()1659 public void testStartLaunchIntoPipActivity() { 1660 final ActivityStarter starter = prepareStarter(0, false); 1661 1662 // Create an activity from ActivityOptions#makeLaunchIntoPip 1663 final PictureInPictureParams params = new PictureInPictureParams.Builder() 1664 .build(); 1665 final ActivityOptions opts = ActivityOptions.makeLaunchIntoPip(params); 1666 ActivityRecord targetRecord = new ActivityBuilder(mAtm) 1667 .setActivityOptions(opts) 1668 .build(); 1669 1670 // Start the target launch-into-pip activity from a source 1671 final ActivityRecord sourceRecord = new ActivityBuilder(mAtm).setCreateTask(true).build(); 1672 startActivityInner(starter, targetRecord, sourceRecord, opts, 1673 null /* inTask */, null /* inTaskFragment */); 1674 1675 // Verify the ActivityRecord#getLaunchIntoPipHostActivity points to sourceRecord. 1676 assertThat(targetRecord.getLaunchIntoPipHostActivity()).isNotNull(); 1677 assertEquals(targetRecord.getLaunchIntoPipHostActivity(), sourceRecord); 1678 } 1679 1680 @Test testResultCanceledWhenNotAllowedStartingActivity()1681 public void testResultCanceledWhenNotAllowedStartingActivity() { 1682 final Task task = new TaskBuilder(mSupervisor).build(); 1683 final ActivityStarter starter = prepareStarter(0, false); 1684 final ActivityRecord targetRecord = new ActivityBuilder(mAtm).build(); 1685 final ActivityRecord sourceRecord = new ActivityBuilder(mAtm).setTask(task).build(); 1686 targetRecord.resultTo = sourceRecord; 1687 1688 // Abort the activity start and ensure the sourceRecord gets the result (RESULT_CANCELED). 1689 spyOn(starter); 1690 doReturn(START_ABORTED).when(starter).isAllowedToStart(any(), anyBoolean(), any()); 1691 startActivityInner(starter, targetRecord, sourceRecord, null /* options */, 1692 null /* inTask */, null /* inTaskFragment */); 1693 verify(sourceRecord).sendResult(anyInt(), any(), anyInt(), eq(RESULT_CANCELED), any(), 1694 any()); 1695 } 1696 1697 @Test testCanEmbedActivity()1698 public void testCanEmbedActivity() { 1699 final Size minDimensions = new Size(1000, 1000); 1700 final WindowLayout windowLayout = new WindowLayout(0, 0, 0, 0, 0, 1701 minDimensions.getWidth(), minDimensions.getHeight()); 1702 final ActivityRecord starting = new ActivityBuilder(mAtm) 1703 .setUid(UNIMPORTANT_UID) 1704 .setWindowLayout(windowLayout) 1705 .build(); 1706 1707 // Task fragment hasn't attached to a task yet. Start activity to a new task. 1708 TaskFragment taskFragment = new TaskFragmentBuilder(mAtm).build(); 1709 final Task task = new TaskBuilder(mSupervisor).build(); 1710 1711 assertEquals(EMBEDDING_DISALLOWED_NEW_TASK, 1712 canEmbedActivity(taskFragment, starting, task)); 1713 1714 // Starting activity is going to be started on a task different from task fragment's parent 1715 // task. Start activity to a new task. 1716 task.addChild(taskFragment, POSITION_TOP); 1717 final Task newTask = new TaskBuilder(mSupervisor).build(); 1718 1719 assertEquals(EMBEDDING_DISALLOWED_NEW_TASK, 1720 canEmbedActivity(taskFragment, starting, newTask)); 1721 1722 // Make task fragment bounds exceed task bounds. 1723 final Rect taskBounds = task.getBounds(); 1724 taskFragment.setBounds(taskBounds.left, taskBounds.top, taskBounds.right + 1, 1725 taskBounds.bottom + 1); 1726 1727 assertEquals(EMBEDDING_DISALLOWED_UNTRUSTED_HOST, 1728 canEmbedActivity(taskFragment, starting, task)); 1729 1730 taskFragment.setBounds(taskBounds); 1731 starting.info.flags |= FLAG_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING; 1732 1733 assertEquals(EMBEDDING_ALLOWED, canEmbedActivity(taskFragment, starting, task)); 1734 1735 starting.info.flags &= ~FLAG_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING; 1736 // Set task fragment's uid as the same as starting activity's uid. 1737 taskFragment.setTaskFragmentOrganizer(mock(TaskFragmentOrganizerToken.class), 1738 UNIMPORTANT_UID, "test"); 1739 1740 assertEquals(EMBEDDING_ALLOWED, canEmbedActivity(taskFragment, starting, task)); 1741 1742 // Make task fragment bounds smaller than starting activity's minimum dimensions 1743 taskFragment.setBounds(0, 0, minDimensions.getWidth() - 1, minDimensions.getHeight() - 1); 1744 1745 assertEquals(EMBEDDING_DISALLOWED_MIN_DIMENSION_VIOLATION, 1746 canEmbedActivity(taskFragment, starting, task)); 1747 } 1748 1749 @Test testRecordActivityMovementBeforeDeliverToTop()1750 public void testRecordActivityMovementBeforeDeliverToTop() { 1751 // Mock recents as task is only marked to be in recents 1752 mAtm.mTaskSupervisor.setRecentTasks(mock(RecentTasks.class)); 1753 1754 final Task task = new TaskBuilder(mAtm.mTaskSupervisor).build(); 1755 final ActivityRecord activityBot = new ActivityBuilder(mAtm).setTask(task).build(); 1756 final ActivityRecord activityTop = new ActivityBuilder(mAtm).setTask(task).build(); 1757 1758 activityBot.setVisible(false); 1759 activityBot.setVisibleRequested(false); 1760 1761 assertTrue(activityTop.isVisible()); 1762 assertTrue(activityTop.isVisibleRequested()); 1763 1764 final ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_REORDER_TO_FRONT 1765 | FLAG_ACTIVITY_NEW_TASK, false /* mockGetRootTask */); 1766 starter.mStartActivity = activityBot; 1767 task.inRecents = true; 1768 starter.setInTask(task); 1769 starter.getIntent().setComponent(activityBot.mActivityComponent); 1770 final int result = starter.setReason("testRecordActivityMovement").execute(); 1771 1772 assertEquals(START_DELIVERED_TO_TOP, result); 1773 assertNotNull(starter.mMovedToTopActivity); 1774 1775 final ActivityStarter starter2 = prepareStarter(FLAG_ACTIVITY_REORDER_TO_FRONT 1776 | FLAG_ACTIVITY_NEW_TASK, false /* mockGetRootTask */); 1777 starter2.setInTask(task); 1778 starter2.getIntent().setComponent(activityBot.mActivityComponent); 1779 final int result2 = starter2.setReason("testRecordActivityMovement").execute(); 1780 1781 assertEquals(START_DELIVERED_TO_TOP, result2); 1782 assertNull(starter2.mMovedToTopActivity); 1783 } 1784 1785 /** 1786 * Tests a task with specific display category exist in system and then launching another 1787 * activity with the same affinity but without define the display category. Make sure the 1788 * lunching activity is placed on the different task. 1789 */ 1790 @Test testLaunchActivityWithoutDisplayCategory()1791 public void testLaunchActivityWithoutDisplayCategory() { 1792 final ActivityInfo info = new ActivityInfo(); 1793 info.applicationInfo = new ApplicationInfo(); 1794 info.taskAffinity = ActivityRecord.computeTaskAffinity("test", DEFAULT_FAKE_UID); 1795 info.requiredDisplayCategory = "automotive"; 1796 final Task task = new TaskBuilder(mSupervisor).setCreateActivity(true).setActivityInfo(info) 1797 .build(); 1798 1799 final ActivityRecord target = new ActivityBuilder(mAtm).setAffinity(info.taskAffinity) 1800 .build(); 1801 final ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK, false); 1802 spyOn(starter); 1803 doReturn(START_SUCCESS).when(starter).isAllowedToStart(any(), anyBoolean(), any()); 1804 startActivityInner(starter, target, null /* source */, null /* options */, 1805 null /* inTask */, null /* inTaskFragment */); 1806 1807 assertNotEquals(task, target.getTask()); 1808 } 1809 1810 /** 1811 * Tests a task with a specific display category exist in the system and then launches another 1812 * activity with the different display category. Make sure the launching activity is not placed 1813 * on the sourceRecord's task. 1814 */ 1815 @Test testLaunchActivityWithDifferentDisplayCategory()1816 public void testLaunchActivityWithDifferentDisplayCategory() { 1817 final ActivityInfo info = new ActivityInfo(); 1818 info.applicationInfo = new ApplicationInfo(); 1819 info.taskAffinity = ActivityRecord.computeTaskAffinity("test", DEFAULT_FAKE_UID); 1820 info.requiredDisplayCategory = "automotive"; 1821 final Task task = new TaskBuilder(mSupervisor).setCreateActivity(true).setActivityInfo(info) 1822 .build(); 1823 1824 final ActivityRecord target = new ActivityBuilder(mAtm).setRequiredDisplayCategory("auto") 1825 .setAffinity(info.taskAffinity).build(); 1826 final ActivityStarter starter = prepareStarter(0, false); 1827 spyOn(starter); 1828 doReturn(START_SUCCESS).when(starter).isAllowedToStart(any(), anyBoolean(), any()); 1829 startActivityInner(starter, target, task.getBottomMostActivity(), null /* options */, 1830 null /* inTask */, null /* inTaskFragment */); 1831 1832 assertNotEquals(task, target.getTask()); 1833 } 1834 1835 /** 1836 * Tests a task with specific display category exist in system and then launching another 1837 * activity with the same display category. Make sure the launching activity is placed on the 1838 * same task. 1839 */ 1840 @Test testLaunchActivityWithSameDisplayCategory()1841 public void testLaunchActivityWithSameDisplayCategory() { 1842 final ActivityInfo info = new ActivityInfo(); 1843 info.applicationInfo = new ApplicationInfo(); 1844 info.taskAffinity = ActivityRecord.computeTaskAffinity("test", DEFAULT_FAKE_UID); 1845 info.requiredDisplayCategory = "automotive"; 1846 final Task task = new TaskBuilder(mSupervisor).setCreateActivity(true).setActivityInfo(info) 1847 .build(); 1848 1849 final ActivityRecord target = new ActivityBuilder(mAtm) 1850 .setRequiredDisplayCategory(info.requiredDisplayCategory) 1851 .setAffinity(info.taskAffinity).build(); 1852 1853 final ActivityStarter starter = prepareStarter(0, false); 1854 spyOn(starter); 1855 doReturn(START_SUCCESS).when(starter).isAllowedToStart(any(), anyBoolean(), any()); 1856 startActivityInner(starter, target, task.getBottomMostActivity(), null /* options */, 1857 null /* inTask */, null /* inTaskFragment */); 1858 1859 assertEquals(task, target.getTask()); 1860 } 1861 1862 /** 1863 * Tests a task with specific display category exist in system and launching activity into the 1864 * specific task within inTask attribute. Make sure the activity is not placed on the task since 1865 * the display category is different. 1866 */ 1867 @Test testLaunchActivityInTaskWithDisplayCategory()1868 public void testLaunchActivityInTaskWithDisplayCategory() { 1869 final ActivityInfo info = new ActivityInfo(); 1870 info.applicationInfo = new ApplicationInfo(); 1871 info.requiredDisplayCategory = "automotive"; 1872 final Task inTask = new TaskBuilder(mSupervisor).setActivityInfo(info).build(); 1873 inTask.inRecents = true; 1874 1875 final ActivityStarter starter = prepareStarter(0, false); 1876 spyOn(starter); 1877 doReturn(START_SUCCESS).when(starter).isAllowedToStart(any(), anyBoolean(), any()); 1878 final ActivityRecord target = new ActivityBuilder(mAtm).build(); 1879 startActivityInner(starter, target, null /* source */, null /* options */, inTask, 1880 null /* inTaskFragment */); 1881 1882 assertNotEquals(inTask, target.getTask()); 1883 } 1884 1885 /** 1886 * Tests a task without a specific display category exist in the system and launches activity 1887 * with display category into the task within the inTask attribute. Make sure the activity is 1888 * not placed on the task since the display category is different. 1889 */ 1890 @Test testLaunchDisplayCategoryActivityInTask()1891 public void testLaunchDisplayCategoryActivityInTask() { 1892 final Task inTask = new TaskBuilder(mSupervisor).build(); 1893 inTask.inRecents = true; 1894 1895 final ActivityStarter starter = prepareStarter(0, false); 1896 spyOn(starter); 1897 doReturn(START_SUCCESS).when(starter).isAllowedToStart(any(), anyBoolean(), any()); 1898 final ActivityRecord target = new ActivityBuilder(mAtm).setRequiredDisplayCategory("auto") 1899 .build(); 1900 startActivityInner(starter, target, null /* source */, null /* options */, inTask, 1901 null /* inTaskFragment */); 1902 1903 assertNotEquals(inTask, target.getTask()); 1904 } 1905 startActivityInner(ActivityStarter starter, ActivityRecord target, ActivityRecord source, ActivityOptions options, Task inTask, TaskFragment inTaskFragment)1906 private static void startActivityInner(ActivityStarter starter, ActivityRecord target, 1907 ActivityRecord source, ActivityOptions options, Task inTask, 1908 TaskFragment inTaskFragment) { 1909 starter.startActivityInner(target, source, null /* voiceSession */, 1910 null /* voiceInteractor */, 0 /* startFlags */, 1911 options, inTask, inTaskFragment, 1912 BackgroundActivityStartController.BAL_ALLOW_DEFAULT, null /* intentGrants */, 1913 -1 /* realCallingUid */); 1914 } 1915 } 1916