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 import static android.view.WindowManager.DISPLAY_IME_POLICY_FALLBACK_DISPLAY; 45 import static android.view.WindowManager.DISPLAY_IME_POLICY_HIDE; 46 import static android.view.WindowManager.DISPLAY_IME_POLICY_LOCAL; 47 48 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; 49 50 import static com.android.cts.mockime.ImeEventStreamTestUtils.editorMatcher; 51 import static com.android.cts.mockime.ImeEventStreamTestUtils.notExpectEvent; 52 53 import static org.junit.Assert.assertEquals; 54 import static org.junit.Assert.assertFalse; 55 import static org.junit.Assert.assertNotEquals; 56 import static org.junit.Assert.assertNull; 57 import static org.junit.Assert.assertTrue; 58 import static org.junit.Assert.fail; 59 import static org.junit.Assume.assumeTrue; 60 61 import android.app.ActivityManager; 62 import android.content.ComponentName; 63 import android.content.Context; 64 import android.content.Intent; 65 import android.graphics.Rect; 66 import android.os.Bundle; 67 import android.platform.test.annotations.Presubmit; 68 import android.server.wm.WindowManagerState.DisplayContent; 69 import android.server.wm.WindowManagerState.ActivityTask; 70 import android.server.wm.CommandSession.ActivitySession; 71 import android.server.wm.TestJournalProvider.TestJournalContainer; 72 import android.view.Display; 73 import android.view.View; 74 import android.view.ViewGroup; 75 import android.view.WindowManager; 76 import android.widget.EditText; 77 78 import com.android.compatibility.common.util.SystemUtil; 79 import com.android.compatibility.common.util.TestUtils; 80 import com.android.cts.mockime.ImeEventStream; 81 import com.android.cts.mockime.MockImeSession; 82 83 import org.junit.Before; 84 import org.junit.Test; 85 86 import java.util.concurrent.TimeUnit; 87 88 /** 89 * Build/Install/Run: 90 * atest CtsWindowManagerDeviceTestCases:MultiDisplaySecurityTests 91 * 92 * Tests if be allowed to launch an activity on multi-display environment. 93 */ 94 @Presubmit 95 @android.server.wm.annotation.Group3 96 public class MultiDisplaySecurityTests extends MultiDisplayTestBase { 97 98 @Before 99 @Override setUp()100 public void setUp() throws Exception { 101 super.setUp(); 102 assumeTrue(supportsMultiDisplay()); 103 } 104 105 /** 106 * Tests launching an activity on a virtual display without special permission must not be 107 * allowed. 108 */ 109 @Test testLaunchWithoutPermissionOnVirtualDisplayByOwner()110 public void testLaunchWithoutPermissionOnVirtualDisplayByOwner() { 111 // Create new virtual display. 112 final DisplayContent newDisplay = createManagedVirtualDisplaySession().createDisplay(); 113 114 separateTestJournal(); 115 116 // Try to launch an activity and check if security exception was triggered. 117 getLaunchActivityBuilder() 118 .setUseBroadcastReceiver(LAUNCH_BROADCAST_RECEIVER, LAUNCH_BROADCAST_ACTION) 119 .setDisplayId(newDisplay.mId) 120 .setTargetActivity(TEST_ACTIVITY) 121 .execute(); 122 assertSecurityExceptionFromActivityLauncher(); 123 mWmState.computeState(TEST_ACTIVITY); 124 assertFalse("Restricted activity must not be launched", 125 mWmState.containsActivity(TEST_ACTIVITY)); 126 } 127 128 /** 129 * Tests launching an activity on a virtual display without special permission must not be 130 * allowed. 131 */ 132 @Test testLaunchWithoutPermissionOnVirtualDisplay()133 public void testLaunchWithoutPermissionOnVirtualDisplay() { 134 // Create new virtual display. 135 final DisplayContent newDisplay = createManagedVirtualDisplaySession().createDisplay(); 136 137 separateTestJournal(); 138 139 // Try to launch an activity and check it security exception was triggered. 140 getLaunchActivityBuilder() 141 .setUseBroadcastReceiver(SECOND_LAUNCH_BROADCAST_RECEIVER, 142 SECOND_LAUNCH_BROADCAST_ACTION) 143 .setDisplayId(newDisplay.mId) 144 .setTargetActivity(TEST_ACTIVITY) 145 .execute(); 146 assertSecurityExceptionFromActivityLauncher(); 147 mWmState.computeState(TEST_ACTIVITY); 148 assertFalse("Restricted activity must not be launched", 149 mWmState.containsActivity(TEST_ACTIVITY)); 150 } 151 152 /** 153 * Tests launching an activity on virtual display and then launching another activity that 154 * doesn't allow embedding - it should fail with security exception. 155 */ 156 @Test testConsequentLaunchActivityFromVirtualDisplayNoEmbedding()157 public void testConsequentLaunchActivityFromVirtualDisplayNoEmbedding() { 158 // Create new virtual display. 159 final DisplayContent newDisplay = createManagedVirtualDisplaySession().createDisplay(); 160 161 // Launch activity on new secondary display. 162 launchActivityOnDisplay(LAUNCHING_ACTIVITY, newDisplay.mId); 163 164 waitAndAssertActivityStateOnDisplay(LAUNCHING_ACTIVITY, STATE_RESUMED, newDisplay.mId, 165 "Activity launched on secondary display must be resumed"); 166 167 separateTestJournal(); 168 169 // Launch second activity from app on secondary display specifying same display id. 170 getLaunchActivityBuilder() 171 .setTargetActivity(SECOND_NO_EMBEDDING_ACTIVITY) 172 .setDisplayId(newDisplay.mId) 173 .execute(); 174 175 assertSecurityExceptionFromActivityLauncher(); 176 } 177 isActivityStartAllowedOnDisplay(int displayId, ComponentName activity)178 private boolean isActivityStartAllowedOnDisplay(int displayId, ComponentName activity) { 179 final Intent intent = new Intent(Intent.ACTION_VIEW).setComponent(activity); 180 return mTargetContext.getSystemService(ActivityManager.class) 181 .isActivityStartAllowedOnDisplay(mTargetContext, displayId, intent); 182 } 183 184 /** 185 * Tests 186 * {@link android.app.ActivityManager#isActivityStartAllowedOnDisplay(Context, int, Intent)} 187 * for simulated display. It is owned by system and is public, so should be accessible. 188 */ 189 @Test testCanAccessSystemOwnedDisplay()190 public void testCanAccessSystemOwnedDisplay() { 191 final DisplayContent newDisplay = createManagedVirtualDisplaySession() 192 .setSimulateDisplay(true) 193 .createDisplay(); 194 195 assertTrue(isActivityStartAllowedOnDisplay(newDisplay.mId, TEST_ACTIVITY)); 196 } 197 198 /** 199 * Tests 200 * {@link android.app.ActivityManager#isActivityStartAllowedOnDisplay(Context, int, Intent)} 201 * for a public virtual display and an activity that doesn't support embedding from shell. 202 */ 203 @Test testCanAccessPublicVirtualDisplayWithInternalPermission()204 public void testCanAccessPublicVirtualDisplayWithInternalPermission() { 205 final DisplayContent newDisplay = createManagedVirtualDisplaySession() 206 .setPublicDisplay(true) 207 .createDisplay(); 208 209 SystemUtil.runWithShellPermissionIdentity( 210 () -> assertTrue(isActivityStartAllowedOnDisplay( 211 newDisplay.mId, SECOND_NO_EMBEDDING_ACTIVITY)), 212 "android.permission.INTERNAL_SYSTEM_WINDOW"); 213 } 214 215 /** 216 * Tests 217 * {@link android.app.ActivityManager#isActivityStartAllowedOnDisplay(Context, int, Intent)} 218 * for a private virtual display and an activity that doesn't support embedding from shell. 219 */ 220 @Test testCanAccessPrivateVirtualDisplayWithInternalPermission()221 public void testCanAccessPrivateVirtualDisplayWithInternalPermission() { 222 final DisplayContent newDisplay = createManagedVirtualDisplaySession() 223 .setPublicDisplay(false) 224 .createDisplay(); 225 226 SystemUtil.runWithShellPermissionIdentity( 227 () -> assertTrue(isActivityStartAllowedOnDisplay( 228 newDisplay.mId, SECOND_NO_EMBEDDING_ACTIVITY)), 229 "android.permission.INTERNAL_SYSTEM_WINDOW"); 230 } 231 232 /** 233 * Tests 234 * {@link android.app.ActivityManager#isActivityStartAllowedOnDisplay(Context, int, Intent)} 235 * for a public virtual display, an activity that supports embedding but the launching entity 236 * does not have required permission to embed an activity from other app. 237 */ 238 @Test testCantAccessPublicVirtualDisplayNoEmbeddingPermission()239 public void testCantAccessPublicVirtualDisplayNoEmbeddingPermission() { 240 final DisplayContent newDisplay = createManagedVirtualDisplaySession() 241 .setPublicDisplay(true) 242 .createDisplay(); 243 244 assertFalse(isActivityStartAllowedOnDisplay(newDisplay.mId, SECOND_ACTIVITY)); 245 } 246 247 /** 248 * Tests 249 * {@link android.app.ActivityManager#isActivityStartAllowedOnDisplay(Context, int, Intent)} 250 * for a public virtual display and an activity that does not support embedding. 251 */ 252 @Test testCantAccessPublicVirtualDisplayActivityEmbeddingNotAllowed()253 public void testCantAccessPublicVirtualDisplayActivityEmbeddingNotAllowed() { 254 final DisplayContent newDisplay = createManagedVirtualDisplaySession() 255 .setPublicDisplay(true) 256 .createDisplay(); 257 258 SystemUtil.runWithShellPermissionIdentity( 259 () -> assertFalse(isActivityStartAllowedOnDisplay( 260 newDisplay.mId, SECOND_NO_EMBEDDING_ACTIVITY)), 261 "android.permission.ACTIVITY_EMBEDDING"); 262 } 263 264 /** 265 * Tests 266 * {@link android.app.ActivityManager#isActivityStartAllowedOnDisplay(Context, int, Intent)} 267 * for a public virtual display and an activity that supports embedding. 268 */ 269 @Test testCanAccessPublicVirtualDisplayActivityEmbeddingAllowed()270 public void testCanAccessPublicVirtualDisplayActivityEmbeddingAllowed() { 271 final DisplayContent newDisplay = createManagedVirtualDisplaySession() 272 .setPublicDisplay(true) 273 .createDisplay(); 274 275 SystemUtil.runWithShellPermissionIdentity( 276 () -> assertTrue(isActivityStartAllowedOnDisplay( 277 newDisplay.mId, SECOND_ACTIVITY)), 278 "android.permission.ACTIVITY_EMBEDDING"); 279 } 280 281 /** 282 * Tests 283 * {@link android.app.ActivityManager#isActivityStartAllowedOnDisplay(Context, int, Intent)} 284 * for a private virtual display. 285 */ 286 @Test testCantAccessPrivateVirtualDisplay()287 public void testCantAccessPrivateVirtualDisplay() { 288 final DisplayContent newDisplay = createManagedVirtualDisplaySession() 289 .setPublicDisplay(false) 290 .createDisplay(); 291 292 assertFalse(isActivityStartAllowedOnDisplay(newDisplay.mId, SECOND_ACTIVITY)); 293 } 294 295 /** 296 * Tests 297 * {@link android.app.ActivityManager#isActivityStartAllowedOnDisplay(Context, int, Intent)} 298 * for a private virtual display to check the start of its own activity. 299 */ 300 @Test testCantAccessPrivateVirtualDisplayByOwner()301 public void testCantAccessPrivateVirtualDisplayByOwner() { 302 final DisplayContent newDisplay = createManagedVirtualDisplaySession() 303 .setPublicDisplay(false) 304 .createDisplay(); 305 306 // Check the embedding call. 307 separateTestJournal(); 308 mContext.sendBroadcast(new Intent(ACTION_TEST_ACTIVITY_START) 309 .setPackage(LAUNCH_BROADCAST_RECEIVER.getPackageName()) 310 .setFlags(Intent.FLAG_RECEIVER_FOREGROUND) 311 .putExtra(EXTRA_COMPONENT_NAME, TEST_ACTIVITY) 312 .putExtra(EXTRA_TARGET_DISPLAY, newDisplay.mId)); 313 314 assertActivityStartCheckResult(false); 315 } 316 317 /** 318 * Tests 319 * {@link android.app.ActivityManager#isActivityStartAllowedOnDisplay(Context, int, Intent)} 320 * for a private virtual display by UID present on that display and target activity that allows 321 * embedding. 322 */ 323 @Test testCanAccessPrivateVirtualDisplayByUidPresentOnDisplayActivityEmbeddingAllowed()324 public void testCanAccessPrivateVirtualDisplayByUidPresentOnDisplayActivityEmbeddingAllowed() { 325 final DisplayContent newDisplay = createManagedVirtualDisplaySession() 326 .setPublicDisplay(false) 327 .createDisplay(); 328 // Launch a test activity into the target display. 329 launchActivityOnDisplay(EMBEDDING_ACTIVITY, newDisplay.mId); 330 331 // Check the embedding call. 332 separateTestJournal(); 333 mContext.sendBroadcast(new Intent(ACTION_EMBEDDING_TEST_ACTIVITY_START) 334 .setFlags(Intent.FLAG_RECEIVER_FOREGROUND) 335 .putExtra(EXTRA_EMBEDDING_COMPONENT_NAME, SECOND_ACTIVITY) 336 .putExtra(EXTRA_EMBEDDING_TARGET_DISPLAY, newDisplay.mId)); 337 338 assertActivityStartCheckResult(true); 339 } 340 341 /** 342 * Tests 343 * {@link android.app.ActivityManager#isActivityStartAllowedOnDisplay(Context, int, Intent)} 344 * for a private virtual display by UID present on that display and target activity that does 345 * not allow embedding. 346 */ 347 @Test testCanAccessPrivateVirtualDisplayByUidPresentOnDisplayActivityEmbeddingNotAllowed()348 public void testCanAccessPrivateVirtualDisplayByUidPresentOnDisplayActivityEmbeddingNotAllowed() 349 throws Exception { 350 final DisplayContent newDisplay = createManagedVirtualDisplaySession() 351 .setPublicDisplay(false) 352 .createDisplay(); 353 // Launch a test activity into the target display. 354 launchActivityOnDisplay(EMBEDDING_ACTIVITY, newDisplay.mId); 355 356 // Check the embedding call. 357 separateTestJournal(); 358 mContext.sendBroadcast(new Intent(ACTION_EMBEDDING_TEST_ACTIVITY_START) 359 .setFlags(Intent.FLAG_RECEIVER_FOREGROUND) 360 .putExtra(EXTRA_EMBEDDING_COMPONENT_NAME, SECOND_NO_EMBEDDING_ACTIVITY) 361 .putExtra(EXTRA_EMBEDDING_TARGET_DISPLAY, newDisplay.mId)); 362 363 assertActivityStartCheckResult(false); 364 } 365 assertActivityStartCheckResult(boolean expected)366 private void assertActivityStartCheckResult(boolean expected) { 367 final String component = ActivityLauncher.TAG; 368 final Bundle resultExtras = Condition.waitForResult( 369 new Condition<Bundle>("activity start check for " + component) 370 .setRetryIntervalMs(500) 371 .setResultSupplier(() -> TestJournalContainer.get(component).extras) 372 .setResultValidator(extras -> extras.containsKey( 373 ActivityLauncher.KEY_IS_ACTIVITY_START_ALLOWED_ON_DISPLAY))); 374 if (resultExtras != null) { 375 assertEquals("Activity start check must match", expected, resultExtras 376 .getBoolean(ActivityLauncher.KEY_IS_ACTIVITY_START_ALLOWED_ON_DISPLAY)); 377 return; 378 } 379 fail("Expected activity start check from " + component + " not found"); 380 } 381 382 @Test testDisplayHasAccess_UIDCanPresentOnPrivateDisplay()383 public void testDisplayHasAccess_UIDCanPresentOnPrivateDisplay() { 384 final VirtualDisplayLauncher virtualDisplayLauncher = 385 mObjectTracker.manage(new VirtualDisplayLauncher()); 386 // Create a virtual private display. 387 final DisplayContent newDisplay = virtualDisplayLauncher 388 .setPublicDisplay(false) 389 .createDisplay(); 390 // Launch an embeddable activity into the private display. 391 // Assert that the UID can present on display. 392 final ActivitySession session1 = virtualDisplayLauncher.launchActivityOnDisplay( 393 DISPLAY_ACCESS_CHECK_EMBEDDING_ACTIVITY, newDisplay); 394 assertEquals("Activity which the UID should accessible on private display", 395 isUidAccesibleOnDisplay(session1), true); 396 397 // Launch another embeddable activity with a different UID, verify that it will be 398 // able to access the display where it was put. 399 // Note that set withShellPermission as true in launchActivityOnDisplay is to 400 // make sure ACTIVITY_EMBEDDING can be granted by shell. 401 final ActivitySession session2 = virtualDisplayLauncher.launchActivityOnDisplay( 402 SECOND_ACTIVITY, newDisplay, 403 bundle -> bundle.putBoolean(EXTRA_DISPLAY_ACCESS_CHECK, true), 404 true /* withShellPermission */, true /* waitForLaunch */); 405 406 // Verify SECOND_ACTIVITY's UID has access to this virtual private display. 407 assertEquals("Second activity which the UID should accessible on private display", 408 isUidAccesibleOnDisplay(session2), true); 409 } 410 411 @Test testDisplayHasAccess_NoAccessWhenUIDNotPresentOnPrivateDisplay()412 public void testDisplayHasAccess_NoAccessWhenUIDNotPresentOnPrivateDisplay() { 413 final VirtualDisplayLauncher virtualDisplayLauncher = 414 mObjectTracker.manage(new VirtualDisplayLauncher()); 415 // Create a virtual private display. 416 final DisplayContent newDisplay = virtualDisplayLauncher 417 .setPublicDisplay(false) 418 .createDisplay(); 419 // Launch an embeddable activity into the private display. 420 // Assume that the UID can access on display. 421 final ActivitySession session1 = virtualDisplayLauncher.launchActivityOnDisplay( 422 DISPLAY_ACCESS_CHECK_EMBEDDING_ACTIVITY, newDisplay); 423 assertEquals("Activity which the UID should accessible on private display", 424 isUidAccesibleOnDisplay(session1), true); 425 426 // Verify SECOND_NO_EMBEDDING_ACTIVITY's UID can't access this virtual private display 427 // since there is no entity with this UID on this display. 428 // Note that set withShellPermission as false in launchActivityOnDisplay is to 429 // prevent activity can launch when INTERNAL_SYSTEM_WINDOW granted by shell case. 430 separateTestJournal(); 431 final ActivitySession session2 = virtualDisplayLauncher.launchActivityOnDisplay( 432 SECOND_NO_EMBEDDING_ACTIVITY, newDisplay, null /* extrasConsumer */, 433 false /* withShellPermission */, false /* waitForLaunch */); 434 assertEquals("Second activity which the UID should not accessible on private display", 435 isUidAccesibleOnDisplay(session2), 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 isUidAccesibleOnDisplay(ActivitySession session)456 private boolean isUidAccesibleOnDisplay(ActivitySession session) { 457 boolean result = false; 458 try { 459 result = session.isUidAccesibleOnDisplay(); 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 defaultDisplayFocusedStackId = mWmState.getFocusedStackId(); 475 ActivityTask frontStack = mWmState.getRootTask( 476 defaultDisplayFocusedStackId); 477 assertEquals("Top stack must remain on primary display", 478 DEFAULT_DISPLAY, frontStack.mDisplayId); 479 480 // Launch activity on new secondary display. 481 launchActivityOnDisplay(TEST_ACTIVITY, newDisplay.mId); 482 483 waitAndAssertActivityStateOnDisplay(TEST_ACTIVITY, STATE_RESUMED, newDisplay.mId, 484 "Test activity must be on secondary display"); 485 assertBothDisplaysHaveResumedActivities(pair(DEFAULT_DISPLAY, VIRTUAL_DISPLAY_ACTIVITY), 486 pair(newDisplay.mId, TEST_ACTIVITY)); 487 488 // Launch other activity with different uid and check it is launched on dynamic stack on 489 // secondary display. 490 final String startCmd = "am start -n " + getActivityName(SECOND_ACTIVITY) 491 + " --display " + newDisplay.mId; 492 executeShellCommand(startCmd); 493 494 waitAndAssertActivityStateOnDisplay(SECOND_ACTIVITY, STATE_RESUMED, newDisplay.mId, 495 "Second activity must be on newly launched app"); 496 assertBothDisplaysHaveResumedActivities(pair(DEFAULT_DISPLAY, VIRTUAL_DISPLAY_ACTIVITY), 497 pair(newDisplay.mId, SECOND_ACTIVITY)); 498 } 499 500 /** Test that launching from app that is on external display is allowed. */ 501 @Test testPermissionLaunchFromAppOnSecondary()502 public void testPermissionLaunchFromAppOnSecondary() { 503 // Create new simulated display. 504 final DisplayContent newDisplay = createManagedVirtualDisplaySession() 505 .setSimulateDisplay(true) 506 .createDisplay(); 507 508 // Launch activity with different uid on secondary display. 509 final String startCmd = "am start -n " + getActivityName(SECOND_ACTIVITY) 510 + " --display " + newDisplay.mId; 511 executeShellCommand(startCmd); 512 513 waitAndAssertTopResumedActivity(SECOND_ACTIVITY, newDisplay.mId, 514 "Top activity must be the newly launched one"); 515 516 // Launch another activity with third different uid from app on secondary display and 517 // check it is launched on secondary display. 518 getLaunchActivityBuilder() 519 .setUseBroadcastReceiver(SECOND_LAUNCH_BROADCAST_RECEIVER, 520 SECOND_LAUNCH_BROADCAST_ACTION) 521 .setDisplayId(newDisplay.mId) 522 .setTargetActivity(THIRD_ACTIVITY) 523 .execute(); 524 525 waitAndAssertTopResumedActivity(THIRD_ACTIVITY, newDisplay.mId, 526 "Top activity must be the newly launched one"); 527 } 528 529 /** Tests that an activity can launch an activity from a different UID into its own task. */ 530 @Test testPermissionLaunchMultiUidTask()531 public void testPermissionLaunchMultiUidTask() { 532 final DisplayContent newDisplay = createManagedVirtualDisplaySession() 533 .setSimulateDisplay(true) 534 .createDisplay(); 535 536 launchActivityOnDisplay(LAUNCHING_ACTIVITY, newDisplay.mId); 537 mWmState.computeState(LAUNCHING_ACTIVITY); 538 539 // Check that the first activity is launched onto the secondary display. 540 final int frontStackId = mWmState.getFrontRootTaskId(newDisplay.mId); 541 ActivityTask frontStack = mWmState.getRootTask(frontStackId); 542 assertEquals("Activity launched on secondary display must be resumed", 543 getActivityName(LAUNCHING_ACTIVITY), frontStack.mResumedActivity); 544 mWmState.assertFocusedStack("Top stack must be on secondary display", frontStackId); 545 546 // Launch an activity from a different UID into the first activity's task. 547 getLaunchActivityBuilder().setTargetActivity(SECOND_ACTIVITY).execute(); 548 549 waitAndAssertTopResumedActivity(SECOND_ACTIVITY, newDisplay.mId, 550 "Top activity must be the newly launched one"); 551 frontStack = mWmState.getRootTask(frontStackId); 552 assertEquals("Secondary display must contain 1 task", 1, 553 mWmState.getDisplay(newDisplay.mId).getRootTasks().size()); 554 } 555 556 /** 557 * Test that launching from app that is not present on external display and doesn't own it to 558 * that external display is not allowed. 559 */ 560 @Test testPermissionLaunchFromDifferentApp()561 public void testPermissionLaunchFromDifferentApp() { 562 // Create new virtual display. 563 final DisplayContent newDisplay = createManagedVirtualDisplaySession().createDisplay(); 564 mWmState.assertVisibility(VIRTUAL_DISPLAY_ACTIVITY, true /* visible */); 565 mWmState.assertFocusedActivity("Virtual display activity must be focused", 566 VIRTUAL_DISPLAY_ACTIVITY); 567 final int defaultDisplayFocusedStackId = mWmState.getFocusedStackId(); 568 ActivityTask frontStack = mWmState.getRootTask( 569 defaultDisplayFocusedStackId); 570 assertEquals("Top stack must remain on primary display", 571 DEFAULT_DISPLAY, frontStack.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 @Test testNoInputConnectionForUntrustedVirtualDisplay()810 public void testNoInputConnectionForUntrustedVirtualDisplay() throws Exception { 811 assumeTrue(MSG_NO_MOCK_IME, supportsInstallableIme()); 812 813 final long NOT_EXPECT_TIMEOUT = TimeUnit.SECONDS.toMillis(2); 814 815 final MockImeSession mockImeSession = createManagedMockImeSession(this); 816 final TestActivitySession<ImeTestActivity> imeTestActivitySession = 817 createManagedTestActivitySession(); 818 // Create a untrusted virtual display and assume the display should not show IME window. 819 final DisplayContent newDisplay = createManagedVirtualDisplaySession() 820 .setPublicDisplay(true).createDisplay(); 821 822 // Launch Ime test activity in virtual display. 823 imeTestActivitySession.launchTestActivityOnDisplay(ImeTestActivity.class, 824 newDisplay.mId); 825 // Verify that activity which lives in untrusted display should not be focused. 826 assertNotEquals("ImeTestActivity should not be focused", 827 mWmState.getFocusedActivity(), 828 imeTestActivitySession.getActivity().getComponentName().toString()); 829 830 // Expect onStartInput won't executed in the IME client. 831 final ImeEventStream stream = mockImeSession.openEventStream(); 832 final EditText editText = imeTestActivitySession.getActivity().mEditText; 833 imeTestActivitySession.runOnMainSyncAndWait( 834 imeTestActivitySession.getActivity()::showSoftInput); 835 notExpectEvent(stream, editorMatcher("onStartInput", 836 editText.getPrivateImeOptions()), NOT_EXPECT_TIMEOUT); 837 838 // Expect onStartInput / showSoftInput would be executed when user tapping on the 839 // untrusted display intentionally. 840 final int[] location = new int[2]; 841 editText.getLocationOnScreen(location); 842 tapOnDisplaySync(location[0], location[1], newDisplay.mId); 843 imeTestActivitySession.runOnMainSyncAndWait( 844 imeTestActivitySession.getActivity()::showSoftInput); 845 waitOrderedImeEventsThenAssertImeShown(stream, DEFAULT_DISPLAY, 846 editorMatcher("onStartInput", editText.getPrivateImeOptions()), 847 event -> "showSoftInput".equals(event.getEventName())); 848 849 // Switch focus to top focused display as default display, verify onStartInput won't 850 // be called since the untrusted display should no longer get focus. 851 tapOnDisplayCenter(DEFAULT_DISPLAY); 852 mWmState.computeState(); 853 assertEquals(DEFAULT_DISPLAY, mWmState.getFocusedDisplayId()); 854 imeTestActivitySession.getActivity().resetPrivateImeOptionsIdentifier(); 855 imeTestActivitySession.runOnMainSyncAndWait( 856 imeTestActivitySession.getActivity()::showSoftInput); 857 notExpectEvent(stream, editorMatcher("onStartInput", 858 editText.getPrivateImeOptions()), NOT_EXPECT_TIMEOUT); 859 } 860 } 861