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