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