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.app.AppOpsManager.MODE_ALLOWED;
20 import static android.app.AppOpsManager.MODE_ERRORED;
21 import static android.server.wm.UiDeviceUtils.pressHomeButton;
22 import static android.server.wm.WindowManagerState.STATE_INITIALIZING;
23 import static android.server.wm.backgroundactivity.appa.Components.APP_A_BACKGROUND_ACTIVITY;
24 import static android.server.wm.backgroundactivity.appa.Components.APP_A_FOREGROUND_ACTIVITY;
25 import static android.server.wm.backgroundactivity.appa.Components.APP_A_SECOND_BACKGROUND_ACTIVITY;
26 import static android.server.wm.backgroundactivity.appa.Components.APP_A_SEND_PENDING_INTENT_RECEIVER;
27 import static android.server.wm.backgroundactivity.appa.Components.APP_A_SIMPLE_ADMIN_RECEIVER;
28 import static android.server.wm.backgroundactivity.appa.Components.APP_A_START_ACTIVITY_RECEIVER;
29 import static android.server.wm.backgroundactivity.appa.Components.ForegroundActivity.ACTION_FINISH_ACTIVITY;
30 import static android.server.wm.backgroundactivity.appa.Components.ForegroundActivity.ACTION_LAUNCH_BACKGROUND_ACTIVITIES;
31 import static android.server.wm.backgroundactivity.appa.Components.ForegroundActivity.LAUNCH_BACKGROUND_ACTIVITY_EXTRA;
32 import static android.server.wm.backgroundactivity.appa.Components.ForegroundActivity.LAUNCH_INTENTS_EXTRA;
33 import static android.server.wm.backgroundactivity.appa.Components.ForegroundActivity.LAUNCH_SECOND_BACKGROUND_ACTIVITY_EXTRA;
34 import static android.server.wm.backgroundactivity.appa.Components.ForegroundActivity.RELAUNCH_FOREGROUND_ACTIVITY_EXTRA;
35 import static android.server.wm.backgroundactivity.appa.Components.ForegroundActivity.START_ACTIVITY_FROM_FG_ACTIVITY_DELAY_MS_EXTRA;
36 import static android.server.wm.backgroundactivity.appa.Components.ForegroundActivity.START_ACTIVITY_FROM_FG_ACTIVITY_NEW_TASK_EXTRA;
37 import static android.server.wm.backgroundactivity.appa.Components.SendPendingIntentReceiver.IS_BROADCAST_EXTRA;
38 import static android.server.wm.backgroundactivity.appa.Components.StartBackgroundActivityReceiver.START_ACTIVITY_DELAY_MS_EXTRA;
39 import static android.server.wm.backgroundactivity.appb.Components.APP_B_FOREGROUND_ACTIVITY;
40 import static android.server.wm.backgroundactivity.common.CommonComponents.EVENT_NOTIFIER_EXTRA;
41 
42 import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
43 import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
44 
45 import static com.google.common.truth.Truth.assertThat;
46 
47 import static org.junit.Assert.assertEquals;
48 import static org.junit.Assert.assertFalse;
49 import static org.junit.Assert.assertNull;
50 import static org.junit.Assert.assertTrue;
51 
52 import android.Manifest;
53 import android.app.UiAutomation;
54 import android.content.ComponentName;
55 import android.content.Intent;
56 import android.content.pm.PackageManager;
57 import android.content.pm.UserInfo;
58 import android.os.ResultReceiver;
59 import android.os.UserManager;
60 import android.platform.test.annotations.Presubmit;
61 import android.platform.test.annotations.SystemUserOnly;
62 import android.server.wm.backgroundactivity.common.CommonComponents.Event;
63 import android.server.wm.backgroundactivity.common.EventReceiver;
64 
65 import androidx.annotation.Nullable;
66 import androidx.test.filters.FlakyTest;
67 import androidx.test.platform.app.InstrumentationRegistry;
68 
69 import com.android.compatibility.common.util.AppOpsUtils;
70 
71 import org.junit.After;
72 import org.junit.Before;
73 import org.junit.Ignore;
74 import org.junit.Test;
75 
76 import java.util.List;
77 import java.util.concurrent.TimeoutException;
78 import java.util.stream.Stream;
79 
80 /**
81  * This class covers all test cases for starting/blocking background activities.
82  * As instrumentation tests started by shell are whitelisted to allow starting background activity,
83  * tests can't be done in this app alone.
84  * Hence, there are 2 extra apps, appA and appB. This class will send commands to appA/appB, for
85  * example, send a broadcast to appA and ask it to start a background activity, and we will monitor
86  * the result and see if it starts an activity successfully.
87  */
88 @Presubmit
89 public class BackgroundActivityLaunchTest extends ActivityManagerTestBase {
90 
91     private static final int ACTIVITY_FOCUS_TIMEOUT_MS = 3000;
92     private static final String APP_A_PACKAGE_NAME = APP_A_FOREGROUND_ACTIVITY.getPackageName();
93     private static final long ACTIVITY_BG_START_GRACE_PERIOD_MS = 10 * 1000;
94     private static final int ACTIVITY_START_TIMEOUT_MS = 5000;
95     private static final int ACTIVITY_NOT_RESUMED_TIMEOUT_MS = 5000;
96 
97     private static final String TEST_PACKAGE_APP_A = "android.server.wm.backgroundactivity.appa";
98     private static final String TEST_PACKAGE_APP_B = "android.server.wm.backgroundactivity.appb";
99     public static final ComponentName APP_A_RELAUNCHING_ACTIVITY =
100             new ComponentName(TEST_PACKAGE_APP_A,
101                     "android.server.wm.backgroundactivity.appa.RelaunchingActivity");
102     public static final ComponentName APP_A_PIP_ACTIVITY =
103             new ComponentName(TEST_PACKAGE_APP_A,
104                     "android.server.wm.backgroundactivity.appa.PipActivity");
105     public static final ComponentName APP_A_VIRTUAL_DISPLAY_ACTIVITY =
106             new ComponentName(TEST_PACKAGE_APP_A,
107                     "android.server.wm.backgroundactivity.appa.VirtualDisplayActivity");
108     private static final String SHELL_PACKAGE = "com.android.shell";
109 
110     /**
111      * Tests can be executed as soon as the device has booted. When that happens the broadcast queue
112      * is long and it takes some time to process the broadcast we just sent.
113      */
114     private static final int BROADCAST_DELIVERY_TIMEOUT_MS = 60000;
115 
116     @Override
117     @Before
setUp()118     public void setUp() throws Exception {
119         // disable SAW appopp for AppA (it's granted autonatically when installed in CTS)
120         AppOpsUtils.setOpMode(APP_A_PACKAGE_NAME, "android:system_alert_window", MODE_ERRORED);
121         assertEquals(AppOpsUtils.getOpMode(APP_A_PACKAGE_NAME, "android:system_alert_window"),
122                 MODE_ERRORED);
123 
124         super.setUp();
125         assertNull(mWmState.getTaskByActivity(APP_A_BACKGROUND_ACTIVITY));
126         assertNull(mWmState.getTaskByActivity(APP_A_FOREGROUND_ACTIVITY));
127         assertNull(mWmState.getTaskByActivity(APP_B_FOREGROUND_ACTIVITY));
128 
129         runShellCommand("cmd deviceidle tempwhitelist -d 100000 "
130                 + APP_A_FOREGROUND_ACTIVITY.getPackageName());
131         runShellCommand("cmd deviceidle tempwhitelist -d 100000 "
132                 + APP_B_FOREGROUND_ACTIVITY.getPackageName());
133     }
134 
135     @After
tearDown()136     public void tearDown() throws Exception {
137         // We do this before anything else, because having an active device owner can prevent us
138         // from being able to force stop apps. (b/142061276)
139         runWithShellPermissionIdentity(() -> {
140             runShellCommand("dpm remove-active-admin --user current "
141                     + APP_A_SIMPLE_ADMIN_RECEIVER.flattenToString());
142         });
143 
144         stopTestPackage(TEST_PACKAGE_APP_A);
145         stopTestPackage(TEST_PACKAGE_APP_B);
146         AppOpsUtils.reset(APP_A_PACKAGE_NAME);
147         AppOpsUtils.reset(SHELL_PACKAGE);
148     }
149 
150     @Test
testBackgroundActivityBlocked()151     public void testBackgroundActivityBlocked() throws Exception {
152         // Start AppA background activity and blocked
153         Intent intent = new Intent();
154         intent.setComponent(APP_A_START_ACTIVITY_RECEIVER);
155         mContext.sendBroadcast(intent);
156         boolean result = waitForActivityFocused(APP_A_BACKGROUND_ACTIVITY);
157         assertFalse("Should not able to launch background activity", result);
158         assertTaskStack(null, APP_A_BACKGROUND_ACTIVITY);
159     }
160 
161     @Test
testStartBgActivity_usingStartActivitiesFromBackgroundPermission()162     public void testStartBgActivity_usingStartActivitiesFromBackgroundPermission()
163             throws Exception {
164         // Disable SAW app op for shell, since that can also allow starting activities from bg.
165         AppOpsUtils.setOpMode(SHELL_PACKAGE, "android:system_alert_window", MODE_ERRORED);
166 
167         // Launch the activity via a shell command, this way the system doesn't have info on which
168         // app launched the activity and thus won't use instrumentation privileges to launch it. But
169         // the shell has the START_ACTIVITIES_FROM_BACKGROUND permission, so we expect it to
170         // succeed.
171         // See testBackgroundActivityBlocked() for a case where an app without the
172         // START_ACTIVITIES_FROM_BACKGROUND permission is blocked from launching the activity from
173         // the background.
174         launchActivity(APP_A_BACKGROUND_ACTIVITY);
175 
176         // If the activity launches, it means the START_ACTIVITIES_FROM_BACKGROUND permission works.
177         assertEquals("Launched activity should be at the top",
178                 ComponentNameUtils.getActivityName(APP_A_BACKGROUND_ACTIVITY),
179                 mWmState.getTopActivityName(0));
180     }
181 
182     @Test
183     @FlakyTest(bugId = 155454710)
testBackgroundActivityNotBlockedWithinGracePeriod()184     public void testBackgroundActivityNotBlockedWithinGracePeriod() throws Exception {
185         // Start AppA foreground activity
186         Intent firstIntent = new Intent();
187         firstIntent.setComponent(APP_A_FOREGROUND_ACTIVITY);
188         firstIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
189         mContext.startActivity(firstIntent);
190         boolean firstResult = waitForActivityFocused(APP_A_FOREGROUND_ACTIVITY);
191         assertTrue("Not able to start foreground activity", firstResult);
192         // Don't press home button to avoid stop app switches
193         mContext.sendBroadcast(new Intent(ACTION_FINISH_ACTIVITY));
194         mWmState.waitAndAssertActivityRemoved(APP_A_FOREGROUND_ACTIVITY);
195         Intent secondIntent = new Intent();
196         secondIntent.setComponent(APP_A_START_ACTIVITY_RECEIVER);
197 
198         mContext.sendBroadcast(secondIntent);
199         boolean secondResult = waitForActivityFocused(APP_A_BACKGROUND_ACTIVITY);
200         assertTrue("Should be able to launch background activity", secondResult);
201     }
202 
203     @Test
testBackgroundActivityNotBlockedWhenSystemAlertWindowGranted()204     public void testBackgroundActivityNotBlockedWhenSystemAlertWindowGranted() throws Exception {
205         // enable appopp for SAW for this test
206         AppOpsUtils.setOpMode(APP_A_PACKAGE_NAME, "android:system_alert_window", MODE_ALLOWED);
207         assertEquals(AppOpsUtils.getOpMode(APP_A_PACKAGE_NAME, "android:system_alert_window"),
208                 MODE_ALLOWED);
209 
210         // Start AppA background activity successfully as the package has SAW
211         Intent intent = new Intent();
212         intent.setComponent(APP_A_START_ACTIVITY_RECEIVER);
213         mContext.sendBroadcast(intent);
214         boolean result = waitForActivityFocused(APP_A_BACKGROUND_ACTIVITY);
215         assertTrue("Not able to start foreground activity", result);
216     }
217 
218     @Test
testBackgroundActivityNotBlockedWhenForegroundActivityExists()219     public void testBackgroundActivityNotBlockedWhenForegroundActivityExists() throws Exception {
220         // Start AppA foreground activity
221         Intent intent = new Intent();
222         intent.setComponent(APP_A_FOREGROUND_ACTIVITY);
223         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
224         mContext.startActivity(intent);
225         boolean result = waitForActivityFocused(APP_A_FOREGROUND_ACTIVITY);
226         assertTrue("Not able to start foreground activity", result);
227         assertTaskStack(new ComponentName[]{APP_A_FOREGROUND_ACTIVITY}, APP_A_FOREGROUND_ACTIVITY);
228 
229         // Start AppA background activity successfully as there's a foreground activity
230         intent = new Intent();
231         intent.setComponent(APP_A_START_ACTIVITY_RECEIVER);
232         mContext.sendBroadcast(intent);
233         result = waitForActivityFocused(APP_A_BACKGROUND_ACTIVITY);
234         assertTrue("Not able to launch background activity", result);
235         assertTaskStack(new ComponentName[]{APP_A_FOREGROUND_ACTIVITY}, APP_A_FOREGROUND_ACTIVITY);
236         assertTaskStack(new ComponentName[]{APP_A_BACKGROUND_ACTIVITY}, APP_A_BACKGROUND_ACTIVITY);
237     }
238 
239     @Test
testActivityNotBlockedWhenForegroundActivityLaunch()240     public void testActivityNotBlockedWhenForegroundActivityLaunch() throws Exception {
241         // Start foreground activity, and foreground activity able to launch background activity
242         // successfully
243         Intent intent = new Intent();
244         intent.setComponent(APP_A_FOREGROUND_ACTIVITY);
245         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
246         intent.putExtra(LAUNCH_BACKGROUND_ACTIVITY_EXTRA, true);
247         mContext.startActivity(intent);
248         boolean result = waitForActivityFocused(APP_A_BACKGROUND_ACTIVITY);
249         assertTrue("Not able to launch background activity", result);
250         assertTaskStack(new ComponentName[]{APP_A_BACKGROUND_ACTIVITY, APP_A_FOREGROUND_ACTIVITY},
251                 APP_A_FOREGROUND_ACTIVITY);
252     }
253 
254     @Test
testActivityBroughtToTopOfTaskWhenLaunchedInTheBackground()255     public void testActivityBroughtToTopOfTaskWhenLaunchedInTheBackground() throws Exception {
256         // Start foreground activity, and foreground activity able to launch background activity
257         // successfully
258         Intent intent = new Intent();
259         intent.setComponent(APP_A_FOREGROUND_ACTIVITY);
260         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
261         mContext.startActivity(intent);
262         boolean result = waitForActivityFocused(ACTIVITY_FOCUS_TIMEOUT_MS,
263                 APP_A_FOREGROUND_ACTIVITY);
264         assertTrue("Not able to launch background activity", result);
265         assertTaskStack(new ComponentName[]{APP_A_FOREGROUND_ACTIVITY}, APP_A_FOREGROUND_ACTIVITY);
266         // We can't resume app switching after pressing home button, otherwise the grace period
267         // will allow the starts.
268         pressHomeAndWaitHomeResumed();
269 
270         mContext.sendBroadcast(getLaunchActivitiesBroadcast(APP_A_BACKGROUND_ACTIVITY));
271 
272         result = waitForActivityFocused(APP_A_FOREGROUND_ACTIVITY);
273         assertFalse("Previously foreground Activity should not be able to make it focused", result);
274         result = waitForActivityFocused(APP_A_BACKGROUND_ACTIVITY);
275         assertFalse("Previously background Activity should not be able to make it focused", result);
276         assertTaskStack(new ComponentName[] {APP_A_BACKGROUND_ACTIVITY, APP_A_FOREGROUND_ACTIVITY},
277                 APP_A_FOREGROUND_ACTIVITY);
278     }
279 
280     @Test
281     @FlakyTest(bugId = 143522449)
testActivityBlockedWhenLaunchedAfterHomePress()282     public void testActivityBlockedWhenLaunchedAfterHomePress() throws Exception {
283         Intent intent = new Intent();
284         intent.setComponent(APP_A_FOREGROUND_ACTIVITY);
285         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
286         intent.putExtra(LAUNCH_BACKGROUND_ACTIVITY_EXTRA, true);
287         intent.putExtra(START_ACTIVITY_FROM_FG_ACTIVITY_DELAY_MS_EXTRA, 2000);
288         intent.putExtra(START_ACTIVITY_FROM_FG_ACTIVITY_NEW_TASK_EXTRA, true);
289         mContext.startActivity(intent);
290         boolean result = waitForActivityFocused(ACTIVITY_FOCUS_TIMEOUT_MS,
291                 APP_A_FOREGROUND_ACTIVITY);
292         assertTrue("Not able to launch background activity", result);
293         assertTaskStack(new ComponentName[]{APP_A_FOREGROUND_ACTIVITY}, APP_A_FOREGROUND_ACTIVITY);
294 
295         // We can't resume app switching after pressing home button, otherwise the grace period
296         // will allow the starts.
297         pressHomeAndWaitHomeResumed();
298 
299         result = waitForActivityFocused(APP_A_FOREGROUND_ACTIVITY);
300         assertFalse("FG activity shouldn't be visible", result);
301         result = waitForActivityFocused(APP_A_BACKGROUND_ACTIVITY);
302         assertFalse("BG activity shouldn't be visible", result);
303         assertTaskStack(new ComponentName[]{APP_A_FOREGROUND_ACTIVITY}, APP_A_FOREGROUND_ACTIVITY);
304         assertTaskStack(null, APP_A_BACKGROUND_ACTIVITY);
305     }
306 
307     @Test
testActivityNotBlockedFromBgActivityInFgTask()308     public void testActivityNotBlockedFromBgActivityInFgTask() {
309         // Launch Activity A, B in the same task with different processes.
310         final Intent intent = new Intent()
311                 .setComponent(APP_A_FOREGROUND_ACTIVITY)
312                 .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
313         mContext.startActivity(intent);
314         mWmState.waitForValidState(APP_A_FOREGROUND_ACTIVITY);
315         mContext.sendBroadcast(getLaunchActivitiesBroadcast(APP_B_FOREGROUND_ACTIVITY));
316         mWmState.waitForValidState(APP_B_FOREGROUND_ACTIVITY);
317         assertTaskStack(new ComponentName[]{APP_B_FOREGROUND_ACTIVITY, APP_A_FOREGROUND_ACTIVITY},
318                 APP_A_FOREGROUND_ACTIVITY);
319 
320         // Refresh last-stop-app-switch-time by returning to home and then make the task foreground.
321         pressHomeAndResumeAppSwitch();
322         mContext.startActivity(intent);
323         mWmState.waitForValidState(APP_B_FOREGROUND_ACTIVITY);
324         // Though process A is in background, it is in a visible Task (top is B) so it should be
325         // able to start activity successfully.
326         mContext.sendBroadcast(new Intent(ACTION_LAUNCH_BACKGROUND_ACTIVITIES)
327                 .putExtra(LAUNCH_INTENTS_EXTRA, new Intent[]{ new Intent()
328                         .setComponent(APP_A_BACKGROUND_ACTIVITY)
329                         .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) }));
330         mWmState.waitForValidState(APP_A_BACKGROUND_ACTIVITY);
331         mWmState.assertFocusedActivity(
332                 "The background activity must be able to launch from a visible task",
333                 APP_A_BACKGROUND_ACTIVITY);
334     }
335 
336     @Test
337     @FlakyTest(bugId = 130800326)
338     @Ignore  // TODO(b/145981637): Make this test work
testActivityBlockedWhenForegroundActivityRestartsItself()339     public void testActivityBlockedWhenForegroundActivityRestartsItself() throws Exception {
340         // Start AppA foreground activity
341         Intent intent = new Intent();
342         intent.setComponent(APP_A_FOREGROUND_ACTIVITY);
343         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
344         intent.putExtra(RELAUNCH_FOREGROUND_ACTIVITY_EXTRA, true);
345         mContext.startActivity(intent);
346         boolean result = waitForActivityFocused(APP_A_FOREGROUND_ACTIVITY);
347         assertTrue("Not able to start foreground activity", result);
348         assertTaskStack(new ComponentName[]{APP_A_FOREGROUND_ACTIVITY}, APP_A_FOREGROUND_ACTIVITY);
349 
350         // The foreground activity will be paused but will attempt to restart itself in onPause()
351         pressHomeAndResumeAppSwitch();
352 
353         result = waitForActivityFocused(APP_A_FOREGROUND_ACTIVITY);
354         assertFalse("Previously foreground Activity should not be able to relaunch itself", result);
355         assertTaskStack(new ComponentName[]{APP_A_FOREGROUND_ACTIVITY}, APP_A_FOREGROUND_ACTIVITY);
356     }
357 
358     @Test
testSecondActivityNotBlockedWhenForegroundActivityLaunch()359     public void testSecondActivityNotBlockedWhenForegroundActivityLaunch() throws Exception {
360         // Start AppA foreground activity, which will immediately launch one activity
361         // and then the second.
362         Intent intent = new Intent();
363         intent.setComponent(APP_A_FOREGROUND_ACTIVITY);
364         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
365         intent.putExtra(LAUNCH_BACKGROUND_ACTIVITY_EXTRA, true);
366         intent.putExtra(LAUNCH_SECOND_BACKGROUND_ACTIVITY_EXTRA, true);
367         mContext.startActivity(intent);
368 
369         boolean result = waitForActivityFocused(APP_A_SECOND_BACKGROUND_ACTIVITY);
370         assertTrue("Not able to launch second background activity", result);
371 
372         waitAndAssertActivityState(APP_A_BACKGROUND_ACTIVITY, STATE_INITIALIZING,
373                 "First activity should have been created");
374         assertTaskStack(
375                 new ComponentName[]{APP_A_SECOND_BACKGROUND_ACTIVITY, APP_A_BACKGROUND_ACTIVITY,
376                         APP_A_FOREGROUND_ACTIVITY}, APP_A_FOREGROUND_ACTIVITY);
377     }
378 
379     @Test
380     @FlakyTest(bugId = 143522449)
testSecondActivityBlockedWhenBackgroundActivityLaunch()381     public void testSecondActivityBlockedWhenBackgroundActivityLaunch() throws Exception {
382         Intent baseActivityIntent = new Intent();
383         baseActivityIntent.setComponent(APP_A_FOREGROUND_ACTIVITY);
384         baseActivityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
385         mContext.startActivity(baseActivityIntent);
386         boolean result = waitForActivityFocused(APP_A_FOREGROUND_ACTIVITY);
387         assertTrue("Not able to start foreground activity", result);
388         assertTaskStack(new ComponentName[]{APP_A_FOREGROUND_ACTIVITY}, APP_A_FOREGROUND_ACTIVITY);
389         // We can't resume app switching after pressing home button, otherwise the grace period
390         // will allow the starts.
391         pressHomeAndWaitHomeResumed();
392 
393         // The activity, now in the background, will attempt to start 2 activities in quick
394         // succession
395         mContext.sendBroadcast(getLaunchActivitiesBroadcast(APP_A_BACKGROUND_ACTIVITY,
396                 APP_A_SECOND_BACKGROUND_ACTIVITY));
397 
398         // There should be 2 activities in the background (not focused) INITIALIZING
399         result = waitForActivityFocused(APP_A_BACKGROUND_ACTIVITY);
400         assertFalse("Activity should not have been launched in the foreground", result);
401         result = waitForActivityFocused(APP_A_SECOND_BACKGROUND_ACTIVITY);
402         assertFalse("Second activity should not have been launched in the foreground", result);
403         assertTaskStack(
404                 new ComponentName[]{APP_A_SECOND_BACKGROUND_ACTIVITY, APP_A_BACKGROUND_ACTIVITY,
405                         APP_A_FOREGROUND_ACTIVITY}, APP_A_FOREGROUND_ACTIVITY);
406     }
407 
408     @Test
testPendingIntentActivityBlocked()409     public void testPendingIntentActivityBlocked() throws Exception {
410         // Cannot start activity by pending intent, as both appA and appB are in background
411         sendPendingIntentActivity();
412         boolean result = waitForActivityFocused(APP_A_BACKGROUND_ACTIVITY);
413         assertFalse("Should not able to launch background activity", result);
414         assertTaskStack(null, APP_A_BACKGROUND_ACTIVITY);
415     }
416 
417     @Test
418     @FlakyTest(bugId = 130800326)
testPendingIntentActivityNotBlocked_appAIsForeground()419     public void testPendingIntentActivityNotBlocked_appAIsForeground() throws Exception {
420         // Start AppA foreground activity
421         Intent intent = new Intent();
422         intent.setComponent(APP_A_FOREGROUND_ACTIVITY);
423         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
424         mContext.startActivity(intent);
425         boolean result = waitForActivityFocused(APP_A_FOREGROUND_ACTIVITY);
426         assertTrue("Not able to start foreground Activity", result);
427         assertTaskStack(new ComponentName[]{APP_A_FOREGROUND_ACTIVITY}, APP_A_FOREGROUND_ACTIVITY);
428 
429         // Send pendingIntent from AppA to AppB, and the AppB launch the pending intent to start
430         // activity in App A
431         sendPendingIntentActivity();
432         result = waitForActivityFocused(APP_A_BACKGROUND_ACTIVITY);
433         assertTrue("Not able to launch background activity", result);
434         assertTaskStack(new ComponentName[]{APP_A_FOREGROUND_ACTIVITY}, APP_A_FOREGROUND_ACTIVITY);
435         assertTaskStack(new ComponentName[]{APP_A_BACKGROUND_ACTIVITY}, APP_A_BACKGROUND_ACTIVITY);
436     }
437 
438     @Test
testPendingIntentBroadcastActivityNotBlocked_appBIsForeground()439     public void testPendingIntentBroadcastActivityNotBlocked_appBIsForeground() throws Exception {
440         // Start AppB foreground activity
441         Intent intent = new Intent();
442         intent.setComponent(APP_B_FOREGROUND_ACTIVITY);
443         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
444         mContext.startActivity(intent);
445         boolean result = waitForActivityFocused(APP_B_FOREGROUND_ACTIVITY);
446         assertTrue("Not able to start foreground Activity", result);
447         assertTaskStack(new ComponentName[]{APP_B_FOREGROUND_ACTIVITY}, APP_B_FOREGROUND_ACTIVITY);
448 
449         // Send pendingIntent from AppA to AppB, and the AppB launch the pending intent to start
450         // activity in App A
451         sendPendingIntentActivity();
452         result = waitForActivityFocused(APP_A_BACKGROUND_ACTIVITY);
453         assertTrue("Not able to launch background activity", result);
454         assertTaskStack(new ComponentName[]{APP_A_BACKGROUND_ACTIVITY}, APP_A_BACKGROUND_ACTIVITY);
455         assertTaskStack(new ComponentName[]{APP_B_FOREGROUND_ACTIVITY}, APP_B_FOREGROUND_ACTIVITY);
456     }
457 
458     @Test
testPendingIntentBroadcastTimeout_noDelay()459     public void testPendingIntentBroadcastTimeout_noDelay() throws Exception {
460         assertPendingIntentBroadcastTimeoutTest(0, true);
461     }
462 
463     @Test
464     @FlakyTest(bugId = 141344170)
testPendingIntentBroadcastTimeout_delay1s()465     public void testPendingIntentBroadcastTimeout_delay1s() throws Exception {
466         assertPendingIntentBroadcastTimeoutTest(1000, true);
467     }
468 
469     @Test
testPendingIntentBroadcastTimeout_delay12s()470     public void testPendingIntentBroadcastTimeout_delay12s() throws Exception {
471         assertPendingIntentBroadcastTimeoutTest(12000, false);
472     }
473 
474     @Test
testPendingIntentBroadcast_appBIsBackground()475     public void testPendingIntentBroadcast_appBIsBackground() throws Exception {
476         EventReceiver receiver = new EventReceiver(
477                 Event.APP_A_START_BACKGROUND_ACTIVITY_BROADCAST_RECEIVED);
478 
479         // Send pendingIntent from AppA to AppB, and the AppB launch the pending intent to start
480         // activity in App A
481         sendPendingIntentBroadcast(0, receiver.getNotifier());
482 
483         // Waits for final hoop in AppA to start looking for activity, otherwise it could succeed
484         // if the broadcast took long time to get executed (which may happen after boot).
485         receiver.waitForEventOrThrow(BROADCAST_DELIVERY_TIMEOUT_MS);
486         boolean result = waitForActivityFocused(APP_A_BACKGROUND_ACTIVITY);
487         assertFalse("Should not able to launch background activity", result);
488         assertTaskStack(null, APP_A_BACKGROUND_ACTIVITY);
489     }
490 
491     /**
492      * Returns a list of alive users on the device
493      */
getAliveUsers()494     private List<UserInfo> getAliveUsers() {
495         // Setting the CREATE_USERS permission in AndroidManifest.xml has no effect when the test
496         // is run through the CTS harness, so instead adopt it as a shell permission. We use
497         // the CREATE_USERS permission instead of MANAGE_USERS because the shell can never use
498         // MANAGE_USERS.
499         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
500         uiAutomation.adoptShellPermissionIdentity(Manifest.permission.CREATE_USERS);
501         List<UserInfo> userList = mContext.getSystemService(UserManager.class)
502                 .getUsers(/* excludePartial= */ true,
503                         /* excludeDying= */ true,
504                         /* excludePreCreated= */ true);
505         uiAutomation.dropShellPermissionIdentity();
506         return userList;
507     }
508 
509     /**
510      * Removes the guest user from the device if present
511      */
removeGuestUser()512     private void removeGuestUser() {
513         List<UserInfo> userList = getAliveUsers();
514         for (UserInfo info : userList) {
515             if (info.isGuest()) {
516                 removeUser(info.id);
517                 // Device is only allowed to have one alive guest user, so stop if it's found
518                 break;
519             }
520         }
521     }
522 
523     /**
524      * Removes a user from the device given their ID
525      */
removeUser(int userId)526     private void removeUser(int userId) {
527         executeShellCommand(String.format("pm remove-user %d", userId));
528     }
529 
530     @Test
531     @SystemUserOnly(reason = "Device owner must be SYSTEM user")
testDeviceOwner()532     public void testDeviceOwner() throws Exception {
533         // Send pendingIntent from AppA to AppB, and the AppB launch the pending intent to start
534         // activity in App A
535         if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN)) {
536             return;
537         }
538 
539         // Remove existing guest user. The device may already have a guest present if it is
540         // configured with config_guestUserAutoCreated.
541         //
542         // In production flow the DO can only be created before device provisioning finishes
543         // (e.g. during SUW), and we make sure the guest user in only created after the device
544         // provision is finished. Ideally this test would use the provisioning flow and Device
545         // Owner (DO) creation in a similar manner as that of production flow.
546         removeGuestUser();
547 
548         String cmdResult = runShellCommand("dpm set-device-owner --user 0 "
549                 + APP_A_SIMPLE_ADMIN_RECEIVER.flattenToString());
550         assertThat(cmdResult).contains("Success");
551         EventReceiver receiver = new EventReceiver(
552                 Event.APP_A_START_BACKGROUND_ACTIVITY_BROADCAST_RECEIVED);
553         Intent intent = new Intent();
554         intent.setComponent(APP_A_START_ACTIVITY_RECEIVER);
555         intent.putExtra(EVENT_NOTIFIER_EXTRA, receiver.getNotifier());
556 
557         mContext.sendBroadcast(intent);
558 
559         // Waits for final hoop in AppA to start looking for activity
560         receiver.waitForEventOrThrow(BROADCAST_DELIVERY_TIMEOUT_MS);
561         boolean result = waitForActivityFocused(APP_A_BACKGROUND_ACTIVITY);
562         assertTrue("Not able to launch background activity", result);
563         assertTaskStack(new ComponentName[]{APP_A_BACKGROUND_ACTIVITY}, APP_A_BACKGROUND_ACTIVITY);
564     }
565 
566     @Test
testAppCannotStartBgActivityAfterHomeButton()567     public void testAppCannotStartBgActivityAfterHomeButton() throws Exception {
568 
569         Intent intent = new Intent();
570         intent.setComponent(APP_A_RELAUNCHING_ACTIVITY);
571         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
572         mContext.startActivity(intent);
573 
574         assertTrue("Main activity not started", waitUntilForegroundChanged(
575                 TEST_PACKAGE_APP_A, true, ACTIVITY_START_TIMEOUT_MS));
576 
577         // Click home button, and test app activity onPause() will try to start a background
578         // activity, but we expect this will be blocked BAL logic in system, as app cannot start
579         // any background activity even within grace period after pressing home button.
580         pressHomeAndWaitHomeResumed();
581 
582         assertActivityNotResumed();
583     }
584 
585     // Check picture-in-picture(PIP) won't allow to start BAL after pressing home.
586     @Test
testPipCannotStartAfterHomeButton()587     public void testPipCannotStartAfterHomeButton() throws Exception {
588 
589         Intent intent = new Intent();
590         intent.setComponent(APP_A_PIP_ACTIVITY);
591         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
592         mContext.startActivity(intent);
593 
594         assertTrue("Pip activity not started", waitUntilForegroundChanged(
595                 TEST_PACKAGE_APP_A, true, ACTIVITY_START_TIMEOUT_MS));
596 
597         // Click home button, and test app activity onPause() will trigger pip window,
598         // test will will try to start background activity, but we expect the background activity
599         // will be blocked even the app has a visible pip window, as we do not allow background
600         // activity to be started after pressing home button.
601         pressHomeAndWaitHomeResumed();
602 
603         assertActivityNotResumed();
604     }
605 
606     // Check that a presentation on a virtual display won't allow BAL after pressing home.
607     @Test
testVirtualDisplayCannotStartAfterHomeButton()608     public void testVirtualDisplayCannotStartAfterHomeButton() throws Exception {
609         Intent intent = new Intent();
610         intent.setComponent(APP_A_VIRTUAL_DISPLAY_ACTIVITY);
611         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
612         mContext.startActivity(intent);
613 
614         assertTrue("VirtualDisplay activity not started", waitUntilForegroundChanged(
615                 TEST_PACKAGE_APP_A, true, ACTIVITY_START_TIMEOUT_MS));
616 
617         // Click home button, and test app activity onPause() will trigger which tries to launch
618         // the background activity.
619         pressHomeAndWaitHomeResumed();
620 
621         assertActivityNotResumed();
622     }
623 
pressHomeAndWaitHomeResumed()624     private void pressHomeAndWaitHomeResumed() {
625         pressHomeButton();
626         mWmState.waitForHomeActivityVisible();
627     }
628 
checkPackageResumed(String pkg)629     private boolean checkPackageResumed(String pkg) {
630         WindowManagerStateHelper helper = new WindowManagerStateHelper();
631         helper.computeState();
632         return ComponentName.unflattenFromString(
633                 helper.getFocusedActivity()).getPackageName().equals(pkg);
634     }
635 
636     // Return true if the state of the package is changed to target state.
waitUntilForegroundChanged(String targetPkg, boolean toBeResumed, int timeout)637     private boolean waitUntilForegroundChanged(String targetPkg, boolean toBeResumed, int timeout)
638             throws Exception {
639         long startTime = System.currentTimeMillis();
640         while (checkPackageResumed(targetPkg) != toBeResumed) {
641             if (System.currentTimeMillis() - startTime < timeout) {
642                 Thread.sleep(100);
643             } else {
644                 return false;
645             }
646         }
647         return true;
648     }
649 
assertActivityNotResumed()650     private void assertActivityNotResumed() throws Exception {
651         assertFalse("Test activity is resumed",
652                 waitUntilForegroundChanged(TEST_PACKAGE_APP_A, true,
653                         ACTIVITY_NOT_RESUMED_TIMEOUT_MS));
654     }
655 
getLaunchActivitiesBroadcast(ComponentName... componentNames)656     private Intent getLaunchActivitiesBroadcast(ComponentName... componentNames) {
657         Intent broadcastIntent = new Intent(ACTION_LAUNCH_BACKGROUND_ACTIVITIES);
658         Intent[] intents = Stream.of(componentNames)
659                 .map(c -> {
660                     Intent intent = new Intent();
661                     intent.setComponent(c);
662                     return intent;
663                 })
664                 .toArray(Intent[]::new);
665         broadcastIntent.putExtra(LAUNCH_INTENTS_EXTRA, intents);
666         return broadcastIntent;
667     }
668 
pressHomeAndResumeAppSwitch()669     private void pressHomeAndResumeAppSwitch() {
670         // Press home key to ensure stopAppSwitches is called because the last-stop-app-switch-time
671         // is a criteria of allowing background start.
672         pressHomeButton();
673         // Resume the stopped state (it won't affect last-stop-app-switch-time) so we don't need to
674         // wait extra time to prevent the next launch from being delayed.
675         resumeAppSwitches();
676         mWmState.waitForHomeActivityVisible();
677         // Resuming app switches again after home became visible because the previous call might
678         // have raced with pressHomeButton().
679         // TODO(b/155454710): Remove previous call after making sure all the tests don't depend on
680         // the timing here.
681         resumeAppSwitches();
682     }
683 
assertTaskStack(ComponentName[] expectedComponents, ComponentName sourceComponent)684     private void assertTaskStack(ComponentName[] expectedComponents,
685             ComponentName sourceComponent) {
686         if (expectedComponents == null) {
687             assertNull(mWmState.getTaskByActivity(sourceComponent));
688             return;
689         }
690         List<WindowManagerState.Activity> actual = mWmState.getTaskByActivity(
691                 sourceComponent).mActivities;
692         assertEquals(expectedComponents.length, actual.size());
693         int size = expectedComponents.length;
694         for (int i = 0; i < size; i++) {
695             assertEquals(expectedComponents[i].flattenToShortString(), actual.get(i).getName());
696         }
697     }
698 
assertPendingIntentBroadcastTimeoutTest(int delayMs, boolean expectedResult)699     private void assertPendingIntentBroadcastTimeoutTest(int delayMs, boolean expectedResult)
700             throws TimeoutException {
701         // Start AppB foreground activity
702         Intent intent = new Intent();
703         intent.setComponent(APP_B_FOREGROUND_ACTIVITY);
704         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
705         mContext.startActivity(intent);
706         boolean result = waitForActivityFocused(APP_B_FOREGROUND_ACTIVITY);
707         assertTrue("Not able to start foreground Activity", result);
708         assertTaskStack(new ComponentName[]{APP_B_FOREGROUND_ACTIVITY}, APP_B_FOREGROUND_ACTIVITY);
709         EventReceiver receiver = new EventReceiver(
710                 Event.APP_A_START_BACKGROUND_ACTIVITY_BROADCAST_RECEIVED);
711 
712         // Send pendingIntent from AppA to AppB, and the AppB launch the pending intent to start
713         // activity in App A
714         sendPendingIntentBroadcast(delayMs, receiver.getNotifier());
715 
716         // Waits for final hoop in AppA to start looking for activity
717         receiver.waitForEventOrThrow(BROADCAST_DELIVERY_TIMEOUT_MS);
718         result = waitForActivityFocused(ACTIVITY_FOCUS_TIMEOUT_MS + delayMs,
719                 APP_A_BACKGROUND_ACTIVITY);
720         assertEquals(expectedResult, result);
721         if (expectedResult) {
722             assertTaskStack(new ComponentName[]{APP_A_BACKGROUND_ACTIVITY},
723                     APP_A_BACKGROUND_ACTIVITY);
724         } else {
725             assertTaskStack(null, APP_A_BACKGROUND_ACTIVITY);
726         }
727     }
728 
waitForActivityFocused(ComponentName componentName)729     private boolean waitForActivityFocused(ComponentName componentName) {
730         return waitForActivityFocused(ACTIVITY_FOCUS_TIMEOUT_MS, componentName);
731     }
732 
sendPendingIntentActivity()733     private void sendPendingIntentActivity() {
734         Intent intent = new Intent();
735         intent.setComponent(APP_A_SEND_PENDING_INTENT_RECEIVER);
736         intent.putExtra(IS_BROADCAST_EXTRA, false);
737         mContext.sendBroadcast(intent);
738     }
739 
sendPendingIntentBroadcast(int delayMs, @Nullable ResultReceiver eventNotifier)740     private void sendPendingIntentBroadcast(int delayMs, @Nullable ResultReceiver eventNotifier) {
741         Intent intent = new Intent();
742         intent.setComponent(APP_A_SEND_PENDING_INTENT_RECEIVER);
743         intent.putExtra(IS_BROADCAST_EXTRA, true);
744         if (delayMs > 0) {
745             intent.putExtra(START_ACTIVITY_DELAY_MS_EXTRA, delayMs);
746         }
747         intent.putExtra(EVENT_NOTIFIER_EXTRA, eventNotifier);
748         mContext.sendBroadcast(intent);
749     }
750 }
751