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.ComponentNameUtils.getActivityName; 20 import static android.server.wm.MockImeHelper.createManagedMockImeSession; 21 import static android.server.wm.MultiDisplaySystemDecorationTests.ImeTestActivity; 22 import static android.server.wm.ShellCommandHelper.executeShellCommand; 23 import static android.server.wm.WindowManagerState.STATE_RESUMED; 24 import static android.server.wm.app.Components.DISPLAY_ACCESS_CHECK_EMBEDDING_ACTIVITY; 25 import static android.server.wm.app.Components.LAUNCHING_ACTIVITY; 26 import static android.server.wm.app.Components.LAUNCH_BROADCAST_RECEIVER; 27 import static android.server.wm.app.Components.LaunchBroadcastReceiver.ACTION_TEST_ACTIVITY_START; 28 import static android.server.wm.app.Components.LaunchBroadcastReceiver.EXTRA_COMPONENT_NAME; 29 import static android.server.wm.app.Components.LaunchBroadcastReceiver.EXTRA_TARGET_DISPLAY; 30 import static android.server.wm.app.Components.LaunchBroadcastReceiver.LAUNCH_BROADCAST_ACTION; 31 import static android.server.wm.app.Components.TEST_ACTIVITY; 32 import static android.server.wm.app.Components.VIRTUAL_DISPLAY_ACTIVITY; 33 import static android.server.wm.second.Components.EMBEDDING_ACTIVITY; 34 import static android.server.wm.second.Components.EmbeddingActivity.ACTION_EMBEDDING_TEST_ACTIVITY_START; 35 import static android.server.wm.second.Components.EmbeddingActivity.EXTRA_EMBEDDING_COMPONENT_NAME; 36 import static android.server.wm.second.Components.EmbeddingActivity.EXTRA_EMBEDDING_TARGET_DISPLAY; 37 import static android.server.wm.second.Components.SECOND_ACTIVITY; 38 import static android.server.wm.second.Components.SECOND_LAUNCH_BROADCAST_ACTION; 39 import static android.server.wm.second.Components.SECOND_LAUNCH_BROADCAST_RECEIVER; 40 import static android.server.wm.second.Components.SECOND_NO_EMBEDDING_ACTIVITY; 41 import static android.server.wm.second.Components.SecondActivity.EXTRA_DISPLAY_ACCESS_CHECK; 42 import static android.server.wm.third.Components.THIRD_ACTIVITY; 43 import static android.view.Display.DEFAULT_DISPLAY; 44 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; 45 import static android.view.WindowManager.DISPLAY_IME_POLICY_FALLBACK_DISPLAY; 46 import static android.view.WindowManager.DISPLAY_IME_POLICY_HIDE; 47 import static android.view.WindowManager.DISPLAY_IME_POLICY_LOCAL; 48 49 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; 50 51 import static com.android.cts.mockime.ImeEventStreamTestUtils.editorMatcher; 52 import static com.android.cts.mockime.ImeEventStreamTestUtils.notExpectEvent; 53 54 import static org.junit.Assert.assertEquals; 55 import static org.junit.Assert.assertFalse; 56 import static org.junit.Assert.assertNotEquals; 57 import static org.junit.Assert.assertNull; 58 import static org.junit.Assert.assertTrue; 59 import static org.junit.Assert.fail; 60 import static org.junit.Assume.assumeTrue; 61 62 import android.app.ActivityManager; 63 import android.content.ComponentName; 64 import android.content.Context; 65 import android.content.Intent; 66 import android.os.Bundle; 67 import android.platform.test.annotations.Presubmit; 68 import android.server.wm.CommandSession.ActivitySession; 69 import android.server.wm.TestJournalProvider.TestJournalContainer; 70 import android.server.wm.WindowManagerState.DisplayContent; 71 import android.server.wm.WindowManagerState.Task; 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 defaultDisplayFocusedTaskId = mWmState.getFocusedTaskId(); 475 Task frontRootTask = mWmState.getRootTask(defaultDisplayFocusedTaskId); 476 assertEquals("Top root task must remain on primary display", 477 DEFAULT_DISPLAY, frontRootTask.mDisplayId); 478 479 // Launch activity on new secondary display. 480 launchActivityOnDisplay(TEST_ACTIVITY, newDisplay.mId); 481 482 waitAndAssertActivityStateOnDisplay(TEST_ACTIVITY, STATE_RESUMED, newDisplay.mId, 483 "Test activity must be on secondary display"); 484 assertBothDisplaysHaveResumedActivities(pair(DEFAULT_DISPLAY, VIRTUAL_DISPLAY_ACTIVITY), 485 pair(newDisplay.mId, TEST_ACTIVITY)); 486 487 // Launch other activity with different uid and check it is launched on dynamic task on 488 // secondary display. 489 final String startCmd = "am start -n " + getActivityName(SECOND_ACTIVITY) 490 + " --display " + newDisplay.mId; 491 executeShellCommand(startCmd); 492 493 waitAndAssertActivityStateOnDisplay(SECOND_ACTIVITY, STATE_RESUMED, newDisplay.mId, 494 "Second activity must be on newly launched app"); 495 assertBothDisplaysHaveResumedActivities(pair(DEFAULT_DISPLAY, VIRTUAL_DISPLAY_ACTIVITY), 496 pair(newDisplay.mId, SECOND_ACTIVITY)); 497 } 498 499 /** Test that launching from app that is on external display is allowed. */ 500 @Test testPermissionLaunchFromAppOnSecondary()501 public void testPermissionLaunchFromAppOnSecondary() { 502 // Create new simulated display. 503 final DisplayContent newDisplay = createManagedVirtualDisplaySession() 504 .setSimulateDisplay(true) 505 .createDisplay(); 506 507 // Launch activity with different uid on secondary display. 508 final String startCmd = "am start -n " + getActivityName(SECOND_ACTIVITY) 509 + " --display " + newDisplay.mId; 510 executeShellCommand(startCmd); 511 512 waitAndAssertTopResumedActivity(SECOND_ACTIVITY, newDisplay.mId, 513 "Top activity must be the newly launched one"); 514 515 // Launch another activity with third different uid from app on secondary display and 516 // check it is launched on secondary display. 517 getLaunchActivityBuilder() 518 .setUseBroadcastReceiver(SECOND_LAUNCH_BROADCAST_RECEIVER, 519 SECOND_LAUNCH_BROADCAST_ACTION) 520 .setDisplayId(newDisplay.mId) 521 .setTargetActivity(THIRD_ACTIVITY) 522 .execute(); 523 524 waitAndAssertTopResumedActivity(THIRD_ACTIVITY, newDisplay.mId, 525 "Top activity must be the newly launched one"); 526 } 527 528 /** Tests that an activity can launch an activity from a different UID into its own task. */ 529 @Test testPermissionLaunchMultiUidTask()530 public void testPermissionLaunchMultiUidTask() { 531 final DisplayContent newDisplay = createManagedVirtualDisplaySession() 532 .setSimulateDisplay(true) 533 .createDisplay(); 534 535 launchActivityOnDisplay(LAUNCHING_ACTIVITY, newDisplay.mId); 536 mWmState.computeState(LAUNCHING_ACTIVITY); 537 538 // Check that the first activity is launched onto the secondary display. 539 final int frontRootTaskId = mWmState.getFrontRootTaskId(newDisplay.mId); 540 Task frontTask = mWmState.getRootTask(frontRootTaskId); 541 assertEquals("Activity launched on secondary display must be resumed", 542 getActivityName(LAUNCHING_ACTIVITY), frontTask.mResumedActivity); 543 mWmState.assertFocusedRootTask("Top task must be on secondary display", 544 frontRootTaskId); 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 frontTask = mWmState.getRootTask(frontRootTaskId); 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 defaultDisplayFocusedRootTaskId = mWmState.getFocusedTaskId(); 568 Task frontRootTask = mWmState.getRootTask(defaultDisplayFocusedRootTaskId); 569 assertEquals("Top root task must remain on primary display", 570 DEFAULT_DISPLAY, frontRootTask.mDisplayId); 571 572 // Launch activity on new secondary display. 573 launchActivityOnDisplay(TEST_ACTIVITY, newDisplay.mId); 574 waitAndAssertActivityStateOnDisplay(TEST_ACTIVITY, STATE_RESUMED, newDisplay.mId, 575 "Test activity must be the newly launched one"); 576 577 separateTestJournal(); 578 579 // Launch other activity with different uid and check security exception is triggered. 580 getLaunchActivityBuilder() 581 .setUseBroadcastReceiver(SECOND_LAUNCH_BROADCAST_RECEIVER, 582 SECOND_LAUNCH_BROADCAST_ACTION) 583 .setDisplayId(newDisplay.mId) 584 .setTargetActivity(THIRD_ACTIVITY) 585 .execute(); 586 587 assertSecurityExceptionFromActivityLauncher(); 588 } 589 590 /** 591 * Test that only private virtual display can show content with insecure keyguard. 592 */ 593 @Test testFlagShowWithInsecureKeyguardOnPublicVirtualDisplay()594 public void testFlagShowWithInsecureKeyguardOnPublicVirtualDisplay() { 595 // Try to create new show-with-insecure-keyguard public virtual display. 596 final DisplayContent newDisplay = createManagedVirtualDisplaySession() 597 .setPublicDisplay(true) 598 .setCanShowWithInsecureKeyguard(true) 599 .createDisplay(false /* mustBeCreated */); 600 601 // Check that the display is not created. 602 assertNull(newDisplay); 603 } 604 605 /** 606 * Test setting system decoration flag and show IME flag without sufficient permissions. 607 */ 608 @Test testSettingFlagWithoutInternalSystemPermission()609 public void testSettingFlagWithoutInternalSystemPermission() throws Exception { 610 // The reason to use a trusted display is that we can guarantee the security exception 611 // is coming from lacking internal system permission. 612 final DisplayContent trustedDisplay = createManagedVirtualDisplaySession() 613 .setSimulateDisplay(true) 614 .createDisplay(); 615 final WindowManager wm = mTargetContext.getSystemService(WindowManager.class); 616 617 // Verify setting system decorations flag without internal system permission. 618 try { 619 wm.setShouldShowSystemDecors(trustedDisplay.mId, true); 620 621 // Unexpected result, restore flag to avoid affecting other tests. 622 wm.setShouldShowSystemDecors(trustedDisplay.mId, false); 623 TestUtils.waitUntil("Waiting for system decoration flag to be set", 624 5 /* timeoutSecond */, 625 () -> !wm.shouldShowSystemDecors(trustedDisplay.mId)); 626 fail("Should not allow setting system decoration flag without internal system " 627 + "permission"); 628 } catch (SecurityException e) { 629 // Expected security exception. 630 } 631 632 // Verify setting show IME flag without internal system permission. 633 try { 634 wm.setDisplayImePolicy(trustedDisplay.mId, DISPLAY_IME_POLICY_LOCAL); 635 636 // Unexpected result, restore flag to avoid affecting other tests. 637 wm.setDisplayImePolicy(trustedDisplay.mId, DISPLAY_IME_POLICY_FALLBACK_DISPLAY); 638 TestUtils.waitUntil("Waiting for show IME flag to be set", 639 5 /* timeoutSecond */, 640 () -> (wm.getDisplayImePolicy(trustedDisplay.mId) 641 == DISPLAY_IME_POLICY_FALLBACK_DISPLAY)); 642 fail("Should not allow setting show IME flag without internal system permission"); 643 } catch (SecurityException e) { 644 // Expected security exception. 645 } 646 } 647 648 /** 649 * Test getting system decoration flag and show IME flag without sufficient permissions. 650 */ 651 @Test testGettingFlagWithoutInternalSystemPermission()652 public void testGettingFlagWithoutInternalSystemPermission() { 653 // The reason to use a trusted display is that we can guarantee the security exception 654 // is coming from lacking internal system permission. 655 final DisplayContent trustedDisplay = createManagedVirtualDisplaySession() 656 .setSimulateDisplay(true) 657 .createDisplay(); 658 final WindowManager wm = mTargetContext.getSystemService(WindowManager.class); 659 660 // Verify getting system decorations flag without internal system permission. 661 try { 662 wm.shouldShowSystemDecors(trustedDisplay.mId); 663 fail("Only allow internal system to get system decoration flag"); 664 } catch (SecurityException e) { 665 // Expected security exception. 666 } 667 668 // Verify getting show IME flag without internal system permission. 669 try { 670 wm.getDisplayImePolicy(trustedDisplay.mId); 671 fail("Only allow internal system to get show IME flag"); 672 } catch (SecurityException e) { 673 // Expected security exception. 674 } 675 } 676 677 /** 678 * Test setting system decoration flag and show IME flag to the untrusted display. 679 */ 680 @Test testSettingFlagToUntrustedDisplay()681 public void testSettingFlagToUntrustedDisplay() throws Exception { 682 final DisplayContent untrustedDisplay = createManagedVirtualDisplaySession() 683 .createDisplay(); 684 final WindowManager wm = mTargetContext.getSystemService(WindowManager.class); 685 686 // Verify setting system decoration flag to an untrusted display. 687 getInstrumentation().getUiAutomation().adoptShellPermissionIdentity(); 688 try { 689 wm.setShouldShowSystemDecors(untrustedDisplay.mId, true); 690 691 // Unexpected result, restore flag to avoid affecting other tests. 692 wm.setShouldShowSystemDecors(untrustedDisplay.mId, false); 693 TestUtils.waitUntil("Waiting for system decoration flag to be set", 694 5 /* timeoutSecond */, 695 () -> !wm.shouldShowSystemDecors(untrustedDisplay.mId)); 696 fail("Should not allow setting system decoration flag to the untrusted virtual " 697 + "display"); 698 } catch (SecurityException e) { 699 // Expected security exception. 700 } finally { 701 getInstrumentation().getUiAutomation().dropShellPermissionIdentity(); 702 } 703 704 // Verify setting show IME flag to an untrusted display. 705 getInstrumentation().getUiAutomation().adoptShellPermissionIdentity(); 706 try { 707 wm.setDisplayImePolicy(untrustedDisplay.mId, DISPLAY_IME_POLICY_LOCAL); 708 709 // Unexpected result, restore flag to avoid affecting other tests. 710 wm.setDisplayImePolicy(untrustedDisplay.mId, DISPLAY_IME_POLICY_FALLBACK_DISPLAY); 711 TestUtils.waitUntil("Waiting for show IME flag to be set", 712 5 /* timeoutSecond */, 713 () -> (wm.getDisplayImePolicy(untrustedDisplay.mId) 714 == DISPLAY_IME_POLICY_FALLBACK_DISPLAY)); 715 fail("Should not allow setting show IME flag to the untrusted virtual display"); 716 } catch (SecurityException e) { 717 // Expected security exception. 718 } finally { 719 getInstrumentation().getUiAutomation().dropShellPermissionIdentity(); 720 } 721 } 722 723 /** 724 * Test getting system decoration flag and show IME flag from the untrusted display. 725 */ 726 @Test testGettingFlagFromUntrustedDisplay()727 public void testGettingFlagFromUntrustedDisplay() { 728 final DisplayContent untrustedDisplay = createManagedVirtualDisplaySession() 729 .createDisplay(); 730 final WindowManager wm = mTargetContext.getSystemService(WindowManager.class); 731 732 // Verify getting system decoration flag from an untrusted display. 733 SystemUtil.runWithShellPermissionIdentity(() -> assertFalse( 734 "Display should not support showing system decorations", 735 wm.shouldShowSystemDecors(untrustedDisplay.mId))); 736 737 // Verify getting show IME flag from an untrusted display. 738 SystemUtil.runWithShellPermissionIdentity(() -> assertEquals( 739 "Display should not support showing IME window", 740 wm.getDisplayImePolicy(untrustedDisplay.mId), 741 DISPLAY_IME_POLICY_FALLBACK_DISPLAY)); 742 } 743 744 /** 745 * Test setting system decoration flag and show IME flag to the trusted display. 746 */ 747 @Test testSettingFlagToTrustedDisplay()748 public void testSettingFlagToTrustedDisplay() throws Exception { 749 final DisplayContent trustedDisplay = createManagedVirtualDisplaySession() 750 .setSimulateDisplay(true) 751 .createDisplay(); 752 final WindowManager wm = mTargetContext.getSystemService(WindowManager.class); 753 754 // Verify setting system decoration flag to a trusted display. 755 SystemUtil.runWithShellPermissionIdentity(() -> { 756 // Assume the display should not support system decorations by default. 757 assertFalse(wm.shouldShowSystemDecors(trustedDisplay.mId)); 758 759 try { 760 wm.setShouldShowSystemDecors(trustedDisplay.mId, true); 761 TestUtils.waitUntil("Waiting for system decoration flag to be set", 762 5 /* timeoutSecond */, 763 () -> wm.shouldShowSystemDecors(trustedDisplay.mId)); 764 765 assertTrue(wm.shouldShowSystemDecors(trustedDisplay.mId)); 766 } finally { 767 // Restore flag to avoid affecting other tests. 768 wm.setShouldShowSystemDecors(trustedDisplay.mId, false); 769 TestUtils.waitUntil("Waiting for system decoration flag to be set", 770 5 /* timeoutSecond */, 771 () -> !wm.shouldShowSystemDecors(trustedDisplay.mId)); 772 } 773 }); 774 775 // Verify setting show IME flag to a trusted display. 776 SystemUtil.runWithShellPermissionIdentity(() -> { 777 // Assume the display should not show IME window by default. 778 assertEquals(DISPLAY_IME_POLICY_FALLBACK_DISPLAY, 779 wm.getDisplayImePolicy(trustedDisplay.mId)); 780 781 try { 782 wm.setDisplayImePolicy(trustedDisplay.mId, DISPLAY_IME_POLICY_LOCAL); 783 TestUtils.waitUntil("Waiting for show IME flag to be set", 784 5 /* timeoutSecond */, 785 () -> (wm.getDisplayImePolicy(trustedDisplay.mId) 786 == DISPLAY_IME_POLICY_LOCAL)); 787 788 assertEquals(DISPLAY_IME_POLICY_LOCAL, wm.getDisplayImePolicy(trustedDisplay.mId)); 789 790 wm.setDisplayImePolicy(trustedDisplay.mId, DISPLAY_IME_POLICY_HIDE); 791 TestUtils.waitUntil("Waiting for show IME flag to be set", 792 5 /* timeoutSecond */, 793 () -> (wm.getDisplayImePolicy(trustedDisplay.mId) 794 == DISPLAY_IME_POLICY_HIDE)); 795 796 assertEquals(DISPLAY_IME_POLICY_HIDE, wm.getDisplayImePolicy(trustedDisplay.mId)); 797 } finally { 798 // Restore flag to avoid affecting other tests. 799 wm.setDisplayImePolicy(trustedDisplay.mId, DISPLAY_IME_POLICY_FALLBACK_DISPLAY); 800 TestUtils.waitUntil("Waiting for show IME flag to be set", 801 5 /* timeoutSecond */, 802 () -> (wm.getDisplayImePolicy(trustedDisplay.mId) 803 == DISPLAY_IME_POLICY_FALLBACK_DISPLAY)); 804 } 805 }); 806 } 807 808 @Test testNoInputConnectionForUntrustedVirtualDisplay()809 public void testNoInputConnectionForUntrustedVirtualDisplay() throws Exception { 810 assumeTrue(MSG_NO_MOCK_IME, supportsInstallableIme()); 811 812 final long NOT_EXPECT_TIMEOUT = TimeUnit.SECONDS.toMillis(2); 813 814 final MockImeSession mockImeSession = createManagedMockImeSession(this); 815 final TestActivitySession<ImeTestActivity> imeTestActivitySession = 816 createManagedTestActivitySession(); 817 // Create a untrusted virtual display and assume the display should not show IME window. 818 final DisplayContent newDisplay = createManagedVirtualDisplaySession() 819 .setPublicDisplay(true).createDisplay(); 820 821 // Launch Ime test activity in virtual display. 822 imeTestActivitySession.launchTestActivityOnDisplay(ImeTestActivity.class, 823 newDisplay.mId); 824 // Verify that activity which lives in untrusted display should not be focused. 825 assertNotEquals("ImeTestActivity should not be focused", 826 mWmState.getFocusedActivity(), 827 imeTestActivitySession.getActivity().getComponentName().toString()); 828 829 // Expect onStartInput won't executed in the IME client. 830 final ImeEventStream stream = mockImeSession.openEventStream(); 831 final EditText editText = imeTestActivitySession.getActivity().mEditText; 832 imeTestActivitySession.runOnMainSyncAndWait( 833 imeTestActivitySession.getActivity()::showSoftInput); 834 notExpectEvent(stream, editorMatcher("onStartInput", 835 editText.getPrivateImeOptions()), NOT_EXPECT_TIMEOUT); 836 837 // Expect onStartInput / showSoftInput would be executed when user tapping on the 838 // untrusted display intentionally. 839 final int[] location = new int[2]; 840 editText.getLocationOnScreen(location); 841 tapOnDisplaySync(location[0], location[1], newDisplay.mId); 842 imeTestActivitySession.runOnMainSyncAndWait( 843 imeTestActivitySession.getActivity()::showSoftInput); 844 waitOrderedImeEventsThenAssertImeShown(stream, DEFAULT_DISPLAY, 845 editorMatcher("onStartInput", editText.getPrivateImeOptions()), 846 event -> "showSoftInput".equals(event.getEventName())); 847 848 // Switch focus to top focused display as default display, verify onStartInput won't 849 // be called since the untrusted display should no longer get focus. 850 tapOnDisplayCenter(DEFAULT_DISPLAY); 851 mWmState.computeState(); 852 assertEquals(DEFAULT_DISPLAY, mWmState.getFocusedDisplayId()); 853 imeTestActivitySession.getActivity().resetPrivateImeOptionsIdentifier(); 854 imeTestActivitySession.runOnMainSyncAndWait( 855 imeTestActivitySession.getActivity()::showSoftInput); 856 notExpectEvent(stream, editorMatcher("onStartInput", 857 editText.getPrivateImeOptions()), NOT_EXPECT_TIMEOUT); 858 } 859 } 860