Home | History | Annotate | Download | only in wm
      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
     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
     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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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 
    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
    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
    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
    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 
    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
    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
    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
    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
    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
    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 
    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
    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)
    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)
    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)
    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)
    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)
    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