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