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