1 /* 2 * Copyright (C) 2024 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 android.server.wm.multidisplay; 18 19 import static android.server.wm.ComponentNameUtils.getActivityName; 20 import static android.server.wm.ShellCommandHelper.executeShellCommand; 21 import static android.server.wm.WindowManagerState.STATE_RESUMED; 22 import static android.server.wm.app.Components.DISPLAY_ACCESS_CHECK_EMBEDDING_ACTIVITY; 23 import static android.server.wm.app.Components.LAUNCHING_ACTIVITY; 24 import static android.server.wm.app.Components.LAUNCH_BROADCAST_RECEIVER; 25 import static android.server.wm.app.Components.LaunchBroadcastReceiver.ACTION_TEST_ACTIVITY_START; 26 import static android.server.wm.app.Components.LaunchBroadcastReceiver.EXTRA_COMPONENT_NAME; 27 import static android.server.wm.app.Components.LaunchBroadcastReceiver.EXTRA_TARGET_DISPLAY; 28 import static android.server.wm.app.Components.LaunchBroadcastReceiver.LAUNCH_BROADCAST_ACTION; 29 import static android.server.wm.app.Components.TEST_ACTIVITY; 30 import static android.server.wm.app.Components.VIRTUAL_DISPLAY_ACTIVITY; 31 import static android.server.wm.second.Components.EMBEDDING_ACTIVITY; 32 import static android.server.wm.second.Components.EmbeddingActivity.ACTION_EMBEDDING_TEST_ACTIVITY_START; 33 import static android.server.wm.second.Components.EmbeddingActivity.EXTRA_EMBEDDING_COMPONENT_NAME; 34 import static android.server.wm.second.Components.EmbeddingActivity.EXTRA_EMBEDDING_TARGET_DISPLAY; 35 import static android.server.wm.second.Components.SECOND_ACTIVITY; 36 import static android.server.wm.second.Components.SECOND_LAUNCH_BROADCAST_ACTION; 37 import static android.server.wm.second.Components.SECOND_LAUNCH_BROADCAST_RECEIVER; 38 import static android.server.wm.second.Components.SECOND_NO_EMBEDDING_ACTIVITY; 39 import static android.server.wm.second.Components.SecondActivity.EXTRA_DISPLAY_ACCESS_CHECK; 40 import static android.server.wm.third.Components.THIRD_ACTIVITY; 41 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; 42 import static android.view.WindowManager.DISPLAY_IME_POLICY_FALLBACK_DISPLAY; 43 import static android.view.WindowManager.DISPLAY_IME_POLICY_HIDE; 44 import static android.view.WindowManager.DISPLAY_IME_POLICY_LOCAL; 45 46 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; 47 48 import static org.junit.Assert.assertEquals; 49 import static org.junit.Assert.assertFalse; 50 import static org.junit.Assert.assertNull; 51 import static org.junit.Assert.assertTrue; 52 import static org.junit.Assert.fail; 53 import static org.junit.Assume.assumeTrue; 54 55 import android.app.ActivityManager; 56 import android.content.ComponentName; 57 import android.content.Context; 58 import android.content.Intent; 59 import android.os.Bundle; 60 import android.platform.test.annotations.Presubmit; 61 import android.server.wm.ActivityLauncher; 62 import android.server.wm.CommandSession.ActivitySession; 63 import android.server.wm.Condition; 64 import android.server.wm.MultiDisplayTestBase; 65 import android.server.wm.TestJournalProvider.TestJournalContainer; 66 import android.server.wm.WindowManagerState.DisplayContent; 67 import android.server.wm.WindowManagerState.Task; 68 import android.view.Display; 69 import android.view.View; 70 import android.view.ViewGroup; 71 import android.view.WindowManager; 72 73 import com.android.compatibility.common.util.SystemUtil; 74 import com.android.compatibility.common.util.TestUtils; 75 76 import org.junit.Before; 77 import org.junit.Test; 78 79 /** 80 * Build/Install/Run: 81 * atest CtsWindowManagerDeviceMultiDisplay:MultiDisplaySecurityTests 82 * 83 * Tests if be allowed to launch an activity on multi-display environment. 84 */ 85 @Presubmit 86 @android.server.wm.annotation.Group3 87 public class MultiDisplaySecurityTests extends MultiDisplayTestBase { 88 89 @Before 90 @Override setUp()91 public void setUp() throws Exception { 92 super.setUp(); 93 assumeTrue(supportsMultiDisplay()); 94 } 95 96 /** 97 * Tests launching an activity on a virtual display without special permission must not be 98 * allowed. 99 */ 100 @Test testLaunchWithoutPermissionOnVirtualDisplayByOwner()101 public void testLaunchWithoutPermissionOnVirtualDisplayByOwner() { 102 // Create new virtual display. 103 final DisplayContent newDisplay = createManagedVirtualDisplaySession().createDisplay(); 104 105 separateTestJournal(); 106 107 // Try to launch an activity and check if security exception was triggered. 108 getLaunchActivityBuilder() 109 .setUseBroadcastReceiver(LAUNCH_BROADCAST_RECEIVER, LAUNCH_BROADCAST_ACTION) 110 .setDisplayId(newDisplay.mId) 111 .setTargetActivity(TEST_ACTIVITY) 112 .execute(); 113 assertSecurityExceptionFromActivityLauncher(); 114 mWmState.computeState(TEST_ACTIVITY); 115 assertFalse("Restricted activity must not be launched", 116 mWmState.containsActivity(TEST_ACTIVITY)); 117 } 118 119 /** 120 * Tests launching an activity on a virtual display without special permission must not be 121 * allowed. 122 */ 123 @Test testLaunchWithoutPermissionOnVirtualDisplay()124 public void testLaunchWithoutPermissionOnVirtualDisplay() { 125 // Create new virtual display. 126 final DisplayContent newDisplay = createManagedVirtualDisplaySession().createDisplay(); 127 128 separateTestJournal(); 129 130 // Try to launch an activity and check it security exception was triggered. 131 getLaunchActivityBuilder() 132 .setUseBroadcastReceiver(SECOND_LAUNCH_BROADCAST_RECEIVER, 133 SECOND_LAUNCH_BROADCAST_ACTION) 134 .setDisplayId(newDisplay.mId) 135 .setTargetActivity(TEST_ACTIVITY) 136 .execute(); 137 assertSecurityExceptionFromActivityLauncher(); 138 mWmState.computeState(TEST_ACTIVITY); 139 assertFalse("Restricted activity must not be launched", 140 mWmState.containsActivity(TEST_ACTIVITY)); 141 } 142 143 /** 144 * Tests launching an activity on virtual display and then launching another activity that 145 * doesn't allow embedding - it should fail with security exception. 146 */ 147 @Test testConsequentLaunchActivityFromVirtualDisplayNoEmbedding()148 public void testConsequentLaunchActivityFromVirtualDisplayNoEmbedding() { 149 // Create new virtual display. 150 final DisplayContent newDisplay = createManagedVirtualDisplaySession().createDisplay(); 151 152 // Launch activity on new secondary display. 153 launchActivityOnDisplay(LAUNCHING_ACTIVITY, newDisplay.mId); 154 155 waitAndAssertActivityStateOnDisplay(LAUNCHING_ACTIVITY, STATE_RESUMED, newDisplay.mId, 156 "Activity launched on secondary display must be resumed"); 157 158 separateTestJournal(); 159 160 // Launch second activity from app on secondary display specifying same display id. 161 getLaunchActivityBuilder() 162 .setTargetActivity(SECOND_NO_EMBEDDING_ACTIVITY) 163 .setDisplayId(newDisplay.mId) 164 .execute(); 165 166 assertSecurityExceptionFromActivityLauncher(); 167 } 168 isActivityStartAllowedOnDisplay(int displayId, ComponentName activity)169 private boolean isActivityStartAllowedOnDisplay(int displayId, ComponentName activity) { 170 final Intent intent = new Intent(Intent.ACTION_VIEW).setComponent(activity); 171 return mTargetContext.getSystemService(ActivityManager.class) 172 .isActivityStartAllowedOnDisplay(mTargetContext, displayId, intent); 173 } 174 175 /** 176 * Tests 177 * {@link android.app.ActivityManager#isActivityStartAllowedOnDisplay(Context, int, Intent)} 178 * for simulated display. It is owned by system and is public, so should be accessible. 179 */ 180 @Test testCanAccessSystemOwnedDisplay()181 public void testCanAccessSystemOwnedDisplay() { 182 final DisplayContent newDisplay = createManagedVirtualDisplaySession() 183 .setSimulateDisplay(true) 184 .createDisplay(); 185 186 assertTrue(isActivityStartAllowedOnDisplay(newDisplay.mId, TEST_ACTIVITY)); 187 } 188 189 /** 190 * Tests 191 * {@link android.app.ActivityManager#isActivityStartAllowedOnDisplay(Context, int, Intent)} 192 * for a public virtual display and an activity that doesn't support embedding from shell. 193 */ 194 @Test testCanAccessPublicVirtualDisplayWithInternalPermission()195 public void testCanAccessPublicVirtualDisplayWithInternalPermission() { 196 final DisplayContent newDisplay = createManagedVirtualDisplaySession() 197 .setPublicDisplay(true) 198 .createDisplay(); 199 200 SystemUtil.runWithShellPermissionIdentity( 201 () -> assertTrue(isActivityStartAllowedOnDisplay( 202 newDisplay.mId, SECOND_NO_EMBEDDING_ACTIVITY)), 203 "android.permission.INTERNAL_SYSTEM_WINDOW"); 204 } 205 206 /** 207 * Tests 208 * {@link android.app.ActivityManager#isActivityStartAllowedOnDisplay(Context, int, Intent)} 209 * for a private virtual display and an activity that doesn't support embedding from shell. 210 */ 211 @Test testCanAccessPrivateVirtualDisplayWithInternalPermission()212 public void testCanAccessPrivateVirtualDisplayWithInternalPermission() { 213 final DisplayContent newDisplay = createManagedVirtualDisplaySession() 214 .setPublicDisplay(false) 215 .createDisplay(); 216 217 SystemUtil.runWithShellPermissionIdentity( 218 () -> assertTrue(isActivityStartAllowedOnDisplay( 219 newDisplay.mId, SECOND_NO_EMBEDDING_ACTIVITY)), 220 "android.permission.INTERNAL_SYSTEM_WINDOW"); 221 } 222 223 /** 224 * Tests 225 * {@link android.app.ActivityManager#isActivityStartAllowedOnDisplay(Context, int, Intent)} 226 * for a public virtual display, an activity that supports embedding but the launching entity 227 * does not have required permission to embed an activity from other app. 228 */ 229 @Test testCantAccessPublicVirtualDisplayNoEmbeddingPermission()230 public void testCantAccessPublicVirtualDisplayNoEmbeddingPermission() { 231 final DisplayContent newDisplay = createManagedVirtualDisplaySession() 232 .setPublicDisplay(true) 233 .createDisplay(); 234 235 assertFalse(isActivityStartAllowedOnDisplay(newDisplay.mId, SECOND_ACTIVITY)); 236 } 237 238 /** 239 * Tests 240 * {@link android.app.ActivityManager#isActivityStartAllowedOnDisplay(Context, int, Intent)} 241 * for a public virtual display and an activity that does not support embedding. 242 */ 243 @Test testCantAccessPublicVirtualDisplayActivityEmbeddingNotAllowed()244 public void testCantAccessPublicVirtualDisplayActivityEmbeddingNotAllowed() { 245 final DisplayContent newDisplay = createManagedVirtualDisplaySession() 246 .setPublicDisplay(true) 247 .createDisplay(); 248 249 SystemUtil.runWithShellPermissionIdentity( 250 () -> assertFalse(isActivityStartAllowedOnDisplay( 251 newDisplay.mId, SECOND_NO_EMBEDDING_ACTIVITY)), 252 "android.permission.ACTIVITY_EMBEDDING"); 253 } 254 255 /** 256 * Tests 257 * {@link android.app.ActivityManager#isActivityStartAllowedOnDisplay(Context, int, Intent)} 258 * for a public virtual display and an activity that supports embedding. 259 */ 260 @Test testCanAccessPublicVirtualDisplayActivityEmbeddingAllowed()261 public void testCanAccessPublicVirtualDisplayActivityEmbeddingAllowed() { 262 final DisplayContent newDisplay = createManagedVirtualDisplaySession() 263 .setPublicDisplay(true) 264 .createDisplay(); 265 266 SystemUtil.runWithShellPermissionIdentity( 267 () -> assertTrue(isActivityStartAllowedOnDisplay( 268 newDisplay.mId, SECOND_ACTIVITY)), 269 "android.permission.ACTIVITY_EMBEDDING"); 270 } 271 272 /** 273 * Tests 274 * {@link android.app.ActivityManager#isActivityStartAllowedOnDisplay(Context, int, Intent)} 275 * for a private virtual display. 276 */ 277 @Test testCantAccessPrivateVirtualDisplay()278 public void testCantAccessPrivateVirtualDisplay() { 279 final DisplayContent newDisplay = createManagedVirtualDisplaySession() 280 .setPublicDisplay(false) 281 .createDisplay(); 282 283 assertFalse(isActivityStartAllowedOnDisplay(newDisplay.mId, SECOND_ACTIVITY)); 284 } 285 286 /** 287 * Tests 288 * {@link android.app.ActivityManager#isActivityStartAllowedOnDisplay(Context, int, Intent)} 289 * for a private virtual display to check the start of its own activity. 290 */ 291 @Test testCantAccessPrivateVirtualDisplayByOwner()292 public void testCantAccessPrivateVirtualDisplayByOwner() { 293 final DisplayContent newDisplay = createManagedVirtualDisplaySession() 294 .setPublicDisplay(false) 295 .createDisplay(); 296 297 // Check the embedding call. 298 separateTestJournal(); 299 mContext.sendBroadcast(new Intent(ACTION_TEST_ACTIVITY_START) 300 .setPackage(LAUNCH_BROADCAST_RECEIVER.getPackageName()) 301 .setFlags(Intent.FLAG_RECEIVER_FOREGROUND) 302 .putExtra(EXTRA_COMPONENT_NAME, TEST_ACTIVITY) 303 .putExtra(EXTRA_TARGET_DISPLAY, newDisplay.mId)); 304 305 assertActivityStartCheckResult(false); 306 } 307 308 /** 309 * Tests 310 * {@link android.app.ActivityManager#isActivityStartAllowedOnDisplay(Context, int, Intent)} 311 * for a private virtual display by UID present on that display and target activity that allows 312 * embedding. 313 */ 314 @Test testCanAccessPrivateVirtualDisplayByUidPresentOnDisplayActivityEmbeddingAllowed()315 public void testCanAccessPrivateVirtualDisplayByUidPresentOnDisplayActivityEmbeddingAllowed() { 316 final DisplayContent newDisplay = createManagedVirtualDisplaySession() 317 .setPublicDisplay(false) 318 .createDisplay(); 319 // Launch a test activity into the target display. 320 launchActivityOnDisplay(EMBEDDING_ACTIVITY, newDisplay.mId); 321 322 // Check the embedding call. 323 separateTestJournal(); 324 mContext.sendBroadcast(new Intent(ACTION_EMBEDDING_TEST_ACTIVITY_START) 325 .setFlags(Intent.FLAG_RECEIVER_FOREGROUND) 326 .putExtra(EXTRA_EMBEDDING_COMPONENT_NAME, SECOND_ACTIVITY) 327 .putExtra(EXTRA_EMBEDDING_TARGET_DISPLAY, newDisplay.mId)); 328 329 assertActivityStartCheckResult(true); 330 } 331 332 /** 333 * Tests 334 * {@link android.app.ActivityManager#isActivityStartAllowedOnDisplay(Context, int, Intent)} 335 * for a private virtual display by UID present on that display and target activity that does 336 * not allow embedding. 337 */ 338 @Test testCanAccessPrivateVirtualDisplayByUidPresentOnDisplayActivityEmbeddingNotAllowed()339 public void testCanAccessPrivateVirtualDisplayByUidPresentOnDisplayActivityEmbeddingNotAllowed() 340 throws Exception { 341 final DisplayContent newDisplay = createManagedVirtualDisplaySession() 342 .setPublicDisplay(false) 343 .createDisplay(); 344 // Launch a test activity into the target display. 345 launchActivityOnDisplay(EMBEDDING_ACTIVITY, newDisplay.mId); 346 347 // Check the embedding call. 348 separateTestJournal(); 349 mContext.sendBroadcast(new Intent(ACTION_EMBEDDING_TEST_ACTIVITY_START) 350 .setFlags(Intent.FLAG_RECEIVER_FOREGROUND) 351 .putExtra(EXTRA_EMBEDDING_COMPONENT_NAME, SECOND_NO_EMBEDDING_ACTIVITY) 352 .putExtra(EXTRA_EMBEDDING_TARGET_DISPLAY, newDisplay.mId)); 353 354 assertActivityStartCheckResult(false); 355 } 356 assertActivityStartCheckResult(boolean expected)357 private void assertActivityStartCheckResult(boolean expected) { 358 final String component = ActivityLauncher.TAG; 359 final Bundle resultExtras = Condition.waitForResult( 360 new Condition<Bundle>("activity start check for " + component) 361 .setRetryIntervalMs(500) 362 .setResultSupplier(() -> TestJournalContainer.get(component).extras) 363 .setResultValidator(extras -> extras.containsKey( 364 ActivityLauncher.KEY_IS_ACTIVITY_START_ALLOWED_ON_DISPLAY))); 365 if (resultExtras != null) { 366 assertEquals("Activity start check must match", expected, resultExtras 367 .getBoolean(ActivityLauncher.KEY_IS_ACTIVITY_START_ALLOWED_ON_DISPLAY)); 368 return; 369 } 370 fail("Expected activity start check from " + component + " not found"); 371 } 372 373 @Test testDisplayHasAccess_UIDCanPresentOnPrivateDisplay()374 public void testDisplayHasAccess_UIDCanPresentOnPrivateDisplay() { 375 final VirtualDisplayLauncher virtualDisplayLauncher = 376 mObjectTracker.manage(new VirtualDisplayLauncher()); 377 // Create a virtual private display. 378 final DisplayContent newDisplay = virtualDisplayLauncher 379 .setPublicDisplay(false) 380 .createDisplay(); 381 // Launch an embeddable activity into the private display. 382 // Assert that the UID can present on display. 383 final ActivitySession session1 = virtualDisplayLauncher.launchActivityOnDisplay( 384 DISPLAY_ACCESS_CHECK_EMBEDDING_ACTIVITY, newDisplay); 385 assertEquals( 386 "Activity which the UID should accessible on private display", 387 isUidAccessibleOnDisplay(session1), 388 true); 389 390 // Launch another embeddable activity with a different UID, verify that it will be 391 // able to access the display where it was put. 392 // Note that set withShellPermission as true in launchActivityOnDisplay is to 393 // make sure ACTIVITY_EMBEDDING can be granted by shell. 394 final ActivitySession session2 = virtualDisplayLauncher.launchActivityOnDisplay( 395 SECOND_ACTIVITY, newDisplay, 396 bundle -> bundle.putBoolean(EXTRA_DISPLAY_ACCESS_CHECK, true), 397 true /* withShellPermission */, true /* waitForLaunch */); 398 399 // Verify SECOND_ACTIVITY's UID has access to this virtual private display. 400 assertEquals( 401 "Second activity which the UID should accessible on private display", 402 isUidAccessibleOnDisplay(session2), 403 true); 404 } 405 406 @Test testDisplayHasAccess_NoAccessWhenUIDNotPresentOnPrivateDisplay()407 public void testDisplayHasAccess_NoAccessWhenUIDNotPresentOnPrivateDisplay() { 408 final VirtualDisplayLauncher virtualDisplayLauncher = 409 mObjectTracker.manage(new VirtualDisplayLauncher()); 410 // Create a virtual private display. 411 final DisplayContent newDisplay = virtualDisplayLauncher 412 .setPublicDisplay(false) 413 .createDisplay(); 414 // Launch an embeddable activity into the private display. 415 // Assume that the UID can access on display. 416 final ActivitySession session1 = virtualDisplayLauncher.launchActivityOnDisplay( 417 DISPLAY_ACCESS_CHECK_EMBEDDING_ACTIVITY, newDisplay); 418 assertEquals( 419 "Activity which the UID should accessible on private display", 420 isUidAccessibleOnDisplay(session1), 421 true); 422 423 // Verify SECOND_NO_EMBEDDING_ACTIVITY's UID can't access this virtual private display 424 // since there is no entity with this UID on this display. 425 // Note that set withShellPermission as false in launchActivityOnDisplay is to 426 // prevent activity can launch when INTERNAL_SYSTEM_WINDOW granted by shell case. 427 separateTestJournal(); 428 final ActivitySession session2 = virtualDisplayLauncher.launchActivityOnDisplay( 429 SECOND_NO_EMBEDDING_ACTIVITY, newDisplay, null /* extrasConsumer */, 430 false /* withShellPermission */, false /* waitForLaunch */); 431 assertEquals( 432 "Second activity which the UID should not accessible on private display", 433 isUidAccessibleOnDisplay(session2), 434 false); 435 } 436 437 @Test testDisplayHasAccess_ExceptionWhenAddViewWithoutPresentOnPrivateDisplay()438 public void testDisplayHasAccess_ExceptionWhenAddViewWithoutPresentOnPrivateDisplay() { 439 // Create a virtual private display. 440 final DisplayContent newDisplay = createManagedVirtualDisplaySession() 441 .setPublicDisplay(false) 442 .createDisplay(); 443 try { 444 final Display display = mDm.getDisplay(newDisplay.mId); 445 final Context newDisplayContext = mContext.createDisplayContext(display); 446 newDisplayContext.getSystemService(WindowManager.class).addView(new View(mContext), 447 new ViewGroup.LayoutParams(WRAP_CONTENT, WRAP_CONTENT)); 448 } catch (IllegalArgumentException e) { 449 // Exception happened when createDisplayContext with invalid display. 450 return; 451 } 452 fail("UID should not have access to private display without present entities."); 453 } 454 isUidAccessibleOnDisplay(ActivitySession session)455 private boolean isUidAccessibleOnDisplay(ActivitySession session) { 456 boolean result = false; 457 try { 458 result = session.isUidAccessibleOnDisplay(); 459 } catch (RuntimeException e) { 460 // Catch the exception while waiting reply (i.e. timeout) 461 } 462 return result; 463 } 464 465 /** Test that shell is allowed to launch on secondary displays. */ 466 @Test testPermissionLaunchFromShell()467 public void testPermissionLaunchFromShell(){ 468 // Create new virtual display. 469 final DisplayContent newDisplay = createManagedVirtualDisplaySession().createDisplay(); 470 mWmState.assertVisibility(VIRTUAL_DISPLAY_ACTIVITY, true /* visible */); 471 mWmState.assertFocusedActivity("Virtual display activity must be on top", 472 VIRTUAL_DISPLAY_ACTIVITY); 473 final int defaultDisplayFocusedTaskId = mWmState.getFocusedTaskId(); 474 Task frontRootTask = mWmState.getRootTask(defaultDisplayFocusedTaskId); 475 assertEquals("Top root task must remain on main display assigned to the user", 476 getMainDisplayId(), frontRootTask.mDisplayId); 477 478 // Launch activity on new secondary display. 479 launchActivityOnDisplay(TEST_ACTIVITY, newDisplay.mId); 480 481 waitAndAssertActivityStateOnDisplay(TEST_ACTIVITY, STATE_RESUMED, newDisplay.mId, 482 "Test activity must be on secondary display"); 483 assertBothDisplaysHaveResumedActivities(pair(getMainDisplayId(), VIRTUAL_DISPLAY_ACTIVITY), 484 pair(newDisplay.mId, TEST_ACTIVITY)); 485 486 // Launch other activity with different uid and check it is launched on dynamic task on 487 // secondary display. 488 final String startCmd = "am start -n " + getActivityName(SECOND_ACTIVITY) 489 + " --display " + newDisplay.mId + " --user " + mContext.getUserId(); 490 executeShellCommand(startCmd); 491 492 waitAndAssertActivityStateOnDisplay(SECOND_ACTIVITY, STATE_RESUMED, newDisplay.mId, 493 "Second activity must be on newly launched app"); 494 assertBothDisplaysHaveResumedActivities(pair(getMainDisplayId(), VIRTUAL_DISPLAY_ACTIVITY), 495 pair(newDisplay.mId, SECOND_ACTIVITY)); 496 } 497 498 /** Test that launching from app that is on external display is allowed. */ 499 @Test testPermissionLaunchFromAppOnSecondary()500 public void testPermissionLaunchFromAppOnSecondary() { 501 // Create new simulated display. 502 final DisplayContent newDisplay = createManagedVirtualDisplaySession() 503 .setSimulateDisplay(true) 504 .createDisplay(); 505 506 // Launch activity with different uid on secondary display. 507 final String startCmd = "am start -n " + getActivityName(SECOND_ACTIVITY) 508 + " --display " + newDisplay.mId + " --user " + mContext.getUserId(); 509 executeShellCommand(startCmd); 510 511 waitAndAssertResumedAndFocusedActivityOnDisplay(SECOND_ACTIVITY, newDisplay.mId, 512 "Top activity must be the newly launched one"); 513 514 // Launch another activity with third different uid from app on secondary display and 515 // check it is launched on secondary display. 516 getLaunchActivityBuilder() 517 .setUseBroadcastReceiver(SECOND_LAUNCH_BROADCAST_RECEIVER, 518 SECOND_LAUNCH_BROADCAST_ACTION) 519 .setDisplayId(newDisplay.mId) 520 .setTargetActivity(THIRD_ACTIVITY) 521 .execute(); 522 523 waitAndAssertResumedAndFocusedActivityOnDisplay(THIRD_ACTIVITY, newDisplay.mId, 524 "Top activity must be the newly launched one"); 525 } 526 527 /** Tests that an activity can launch an activity from a different UID into its own task. */ 528 @Test testPermissionLaunchMultiUidTask()529 public void testPermissionLaunchMultiUidTask() { 530 final DisplayContent newDisplay = createManagedVirtualDisplaySession() 531 .setSimulateDisplay(true) 532 .createDisplay(); 533 534 launchActivityOnDisplay(LAUNCHING_ACTIVITY, newDisplay.mId); 535 mWmState.computeState(LAUNCHING_ACTIVITY); 536 537 // Check that the first activity is launched onto the secondary display. 538 final int frontRootTaskId = mWmState.getFrontRootTaskId(newDisplay.mId); 539 Task frontTask = mWmState.getRootTask(frontRootTaskId); 540 assertEquals( 541 "Activity launched on secondary display must be resumed", 542 getActivityName(LAUNCHING_ACTIVITY), 543 frontTask.getResumedActivity()); 544 mWmState.assertFocusedRootTask("Top task must be on secondary display", 545 frontRootTaskId); 546 547 // Launch an activity from a different UID into the first activity's task. 548 getLaunchActivityBuilder().setTargetActivity(SECOND_ACTIVITY).execute(); 549 550 waitAndAssertResumedAndFocusedActivityOnDisplay(SECOND_ACTIVITY, newDisplay.mId, 551 "Top activity must be the newly launched one"); 552 frontTask = mWmState.getRootTask(frontRootTaskId); 553 assertEquals("Secondary display must contain 1 task", 1, 554 mWmState.getDisplay(newDisplay.mId).getRootTasks().size()); 555 } 556 557 /** 558 * Test that launching from app that is not present on external display and doesn't own it to 559 * that external display is not allowed. 560 */ 561 @Test testPermissionLaunchFromDifferentApp()562 public void testPermissionLaunchFromDifferentApp() { 563 // Create new virtual display. 564 final DisplayContent newDisplay = createManagedVirtualDisplaySession().createDisplay(); 565 mWmState.assertVisibility(VIRTUAL_DISPLAY_ACTIVITY, true /* visible */); 566 mWmState.assertFocusedActivity("Virtual display activity must be focused", 567 VIRTUAL_DISPLAY_ACTIVITY); 568 final int defaultDisplayFocusedRootTaskId = mWmState.getFocusedTaskId(); 569 Task frontRootTask = mWmState.getRootTask(defaultDisplayFocusedRootTaskId); 570 assertEquals("Top root task must remain on main display assigned to the user", 571 getMainDisplayId(), frontRootTask.mDisplayId); 572 573 // Launch activity on new secondary display. 574 launchActivityOnDisplay(TEST_ACTIVITY, newDisplay.mId); 575 waitAndAssertActivityStateOnDisplay(TEST_ACTIVITY, STATE_RESUMED, newDisplay.mId, 576 "Test activity must be the newly launched one"); 577 578 separateTestJournal(); 579 580 // Launch other activity with different uid and check security exception is triggered. 581 getLaunchActivityBuilder() 582 .setUseBroadcastReceiver(SECOND_LAUNCH_BROADCAST_RECEIVER, 583 SECOND_LAUNCH_BROADCAST_ACTION) 584 .setDisplayId(newDisplay.mId) 585 .setTargetActivity(THIRD_ACTIVITY) 586 .execute(); 587 588 assertSecurityExceptionFromActivityLauncher(); 589 } 590 591 /** 592 * Test that only private virtual display can show content with insecure keyguard. 593 */ 594 @Test testFlagShowWithInsecureKeyguardOnPublicVirtualDisplay()595 public void testFlagShowWithInsecureKeyguardOnPublicVirtualDisplay() { 596 // Try to create new show-with-insecure-keyguard public virtual display. 597 final DisplayContent newDisplay = createManagedVirtualDisplaySession() 598 .setPublicDisplay(true) 599 .setCanShowWithInsecureKeyguard(true) 600 .createDisplay(false /* mustBeCreated */); 601 602 // Check that the display is not created. 603 assertNull(newDisplay); 604 } 605 606 /** 607 * Test setting system decoration flag and show IME flag without sufficient permissions. 608 */ 609 @Test testSettingFlagWithoutInternalSystemPermission()610 public void testSettingFlagWithoutInternalSystemPermission() throws Exception { 611 // The reason to use a trusted display is that we can guarantee the security exception 612 // is coming from lacking internal system permission. 613 final DisplayContent trustedDisplay = createManagedVirtualDisplaySession() 614 .setSimulateDisplay(true) 615 .createDisplay(); 616 final WindowManager wm = mTargetContext.getSystemService(WindowManager.class); 617 618 // Verify setting system decorations flag without internal system permission. 619 try { 620 wm.setShouldShowSystemDecors(trustedDisplay.mId, true); 621 622 // Unexpected result, restore flag to avoid affecting other tests. 623 wm.setShouldShowSystemDecors(trustedDisplay.mId, false); 624 TestUtils.waitUntil("Waiting for system decoration flag to be set", 625 5 /* timeoutSecond */, 626 () -> !wm.shouldShowSystemDecors(trustedDisplay.mId)); 627 fail("Should not allow setting system decoration flag without internal system " 628 + "permission"); 629 } catch (SecurityException e) { 630 // Expected security exception. 631 } 632 633 // Verify setting show IME flag without internal system permission. 634 try { 635 wm.setDisplayImePolicy(trustedDisplay.mId, DISPLAY_IME_POLICY_LOCAL); 636 637 // Unexpected result, restore flag to avoid affecting other tests. 638 wm.setDisplayImePolicy(trustedDisplay.mId, DISPLAY_IME_POLICY_FALLBACK_DISPLAY); 639 TestUtils.waitUntil("Waiting for show IME flag to be set", 640 5 /* timeoutSecond */, 641 () -> (wm.getDisplayImePolicy(trustedDisplay.mId) 642 == DISPLAY_IME_POLICY_FALLBACK_DISPLAY)); 643 fail("Should not allow setting show IME flag without internal system permission"); 644 } catch (SecurityException e) { 645 // Expected security exception. 646 } 647 } 648 649 /** 650 * Test getting system decoration flag and show IME flag without sufficient permissions. 651 */ 652 @Test testGettingFlagWithoutInternalSystemPermission()653 public void testGettingFlagWithoutInternalSystemPermission() { 654 // The reason to use a trusted display is that we can guarantee the security exception 655 // is coming from lacking internal system permission. 656 final DisplayContent trustedDisplay = createManagedVirtualDisplaySession() 657 .setSimulateDisplay(true) 658 .createDisplay(); 659 final WindowManager wm = mTargetContext.getSystemService(WindowManager.class); 660 661 // Verify getting system decorations flag without internal system permission. 662 try { 663 wm.shouldShowSystemDecors(trustedDisplay.mId); 664 fail("Only allow internal system to get system decoration flag"); 665 } catch (SecurityException e) { 666 // Expected security exception. 667 } 668 669 // Verify getting show IME flag without internal system permission. 670 try { 671 wm.getDisplayImePolicy(trustedDisplay.mId); 672 fail("Only allow internal system to get show IME flag"); 673 } catch (SecurityException e) { 674 // Expected security exception. 675 } 676 } 677 678 /** 679 * Test setting system decoration flag and show IME flag to the untrusted display. 680 */ 681 @Test testSettingFlagToUntrustedDisplay()682 public void testSettingFlagToUntrustedDisplay() throws Exception { 683 final DisplayContent untrustedDisplay = createManagedVirtualDisplaySession() 684 .createDisplay(); 685 final WindowManager wm = mTargetContext.getSystemService(WindowManager.class); 686 687 // Verify setting system decoration flag to an untrusted display. 688 getInstrumentation().getUiAutomation().adoptShellPermissionIdentity(); 689 try { 690 wm.setShouldShowSystemDecors(untrustedDisplay.mId, true); 691 692 // Unexpected result, restore flag to avoid affecting other tests. 693 wm.setShouldShowSystemDecors(untrustedDisplay.mId, false); 694 TestUtils.waitUntil("Waiting for system decoration flag to be set", 695 5 /* timeoutSecond */, 696 () -> !wm.shouldShowSystemDecors(untrustedDisplay.mId)); 697 fail("Should not allow setting system decoration flag to the untrusted virtual " 698 + "display"); 699 } catch (SecurityException e) { 700 // Expected security exception. 701 } finally { 702 getInstrumentation().getUiAutomation().dropShellPermissionIdentity(); 703 } 704 705 // Verify setting show IME flag to an untrusted display. 706 getInstrumentation().getUiAutomation().adoptShellPermissionIdentity(); 707 try { 708 wm.setDisplayImePolicy(untrustedDisplay.mId, DISPLAY_IME_POLICY_LOCAL); 709 710 // Unexpected result, restore flag to avoid affecting other tests. 711 wm.setDisplayImePolicy(untrustedDisplay.mId, DISPLAY_IME_POLICY_FALLBACK_DISPLAY); 712 TestUtils.waitUntil("Waiting for show IME flag to be set", 713 5 /* timeoutSecond */, 714 () -> (wm.getDisplayImePolicy(untrustedDisplay.mId) 715 == DISPLAY_IME_POLICY_FALLBACK_DISPLAY)); 716 fail("Should not allow setting show IME flag to the untrusted virtual display"); 717 } catch (SecurityException e) { 718 // Expected security exception. 719 } finally { 720 getInstrumentation().getUiAutomation().dropShellPermissionIdentity(); 721 } 722 } 723 724 /** 725 * Test getting system decoration flag and show IME flag from the untrusted display. 726 */ 727 @Test testGettingFlagFromUntrustedDisplay()728 public void testGettingFlagFromUntrustedDisplay() { 729 final DisplayContent untrustedDisplay = createManagedVirtualDisplaySession() 730 .createDisplay(); 731 final WindowManager wm = mTargetContext.getSystemService(WindowManager.class); 732 733 // Verify getting system decoration flag from an untrusted display. 734 SystemUtil.runWithShellPermissionIdentity(() -> assertFalse( 735 "Display should not support showing system decorations", 736 wm.shouldShowSystemDecors(untrustedDisplay.mId))); 737 738 // Verify getting show IME flag from an untrusted display. 739 SystemUtil.runWithShellPermissionIdentity(() -> assertEquals( 740 "Display should not support showing IME window", 741 wm.getDisplayImePolicy(untrustedDisplay.mId), 742 DISPLAY_IME_POLICY_FALLBACK_DISPLAY)); 743 } 744 745 /** 746 * Test setting system decoration flag and show IME flag to the trusted display. 747 */ 748 @Test testSettingFlagToTrustedDisplay()749 public void testSettingFlagToTrustedDisplay() throws Exception { 750 final DisplayContent trustedDisplay = createManagedVirtualDisplaySession() 751 .setSimulateDisplay(true) 752 .createDisplay(); 753 final WindowManager wm = mTargetContext.getSystemService(WindowManager.class); 754 755 // Verify setting system decoration flag to a trusted display. 756 SystemUtil.runWithShellPermissionIdentity(() -> { 757 // Assume the display should not support system decorations by default. 758 assertFalse(wm.shouldShowSystemDecors(trustedDisplay.mId)); 759 760 try { 761 wm.setShouldShowSystemDecors(trustedDisplay.mId, true); 762 TestUtils.waitUntil("Waiting for system decoration flag to be set", 763 5 /* timeoutSecond */, 764 () -> wm.shouldShowSystemDecors(trustedDisplay.mId)); 765 766 assertTrue(wm.shouldShowSystemDecors(trustedDisplay.mId)); 767 } finally { 768 // Restore flag to avoid affecting other tests. 769 wm.setShouldShowSystemDecors(trustedDisplay.mId, false); 770 TestUtils.waitUntil("Waiting for system decoration flag to be set", 771 5 /* timeoutSecond */, 772 () -> !wm.shouldShowSystemDecors(trustedDisplay.mId)); 773 } 774 }); 775 776 // Verify setting show IME flag to a trusted display. 777 SystemUtil.runWithShellPermissionIdentity(() -> { 778 // Assume the display should not show IME window by default. 779 assertEquals(DISPLAY_IME_POLICY_FALLBACK_DISPLAY, 780 wm.getDisplayImePolicy(trustedDisplay.mId)); 781 782 try { 783 wm.setDisplayImePolicy(trustedDisplay.mId, DISPLAY_IME_POLICY_LOCAL); 784 TestUtils.waitUntil("Waiting for show IME flag to be set", 785 5 /* timeoutSecond */, 786 () -> (wm.getDisplayImePolicy(trustedDisplay.mId) 787 == DISPLAY_IME_POLICY_LOCAL)); 788 789 assertEquals(DISPLAY_IME_POLICY_LOCAL, wm.getDisplayImePolicy(trustedDisplay.mId)); 790 791 wm.setDisplayImePolicy(trustedDisplay.mId, DISPLAY_IME_POLICY_HIDE); 792 TestUtils.waitUntil("Waiting for show IME flag to be set", 793 5 /* timeoutSecond */, 794 () -> (wm.getDisplayImePolicy(trustedDisplay.mId) 795 == DISPLAY_IME_POLICY_HIDE)); 796 797 assertEquals(DISPLAY_IME_POLICY_HIDE, wm.getDisplayImePolicy(trustedDisplay.mId)); 798 } finally { 799 // Restore flag to avoid affecting other tests. 800 wm.setDisplayImePolicy(trustedDisplay.mId, DISPLAY_IME_POLICY_FALLBACK_DISPLAY); 801 TestUtils.waitUntil("Waiting for show IME flag to be set", 802 5 /* timeoutSecond */, 803 () -> (wm.getDisplayImePolicy(trustedDisplay.mId) 804 == DISPLAY_IME_POLICY_FALLBACK_DISPLAY)); 805 } 806 }); 807 } 808 } 809