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