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