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.app.cts;
18 
19 import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_CAMERA;
20 import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION;
21 import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_MICROPHONE;
22 import static android.app.ActivityManager.PROCESS_CAPABILITY_NONE;
23 import static android.app.ActivityManager.PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK;
24 import static android.app.ActivityManager.PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK;
25 import static android.app.stubs.LocalForegroundService.ACTION_START_FGS_RESULT;
26 import static android.app.stubs.LocalForegroundServiceLocation.ACTION_START_FGSL_RESULT;
27 import static android.os.PowerExemptionManager.REASON_PUSH_MESSAGING;
28 import static android.os.PowerExemptionManager.REASON_PUSH_MESSAGING_OVER_QUOTA;
29 import static android.os.PowerExemptionManager.REASON_UNKNOWN;
30 import static android.os.PowerExemptionManager.TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
31 import static android.os.PowerExemptionManager.TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED;
32 import static android.os.PowerExemptionManager.TEMPORARY_ALLOW_LIST_TYPE_NONE;
33 
34 import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
35 
36 import static junit.framework.Assert.assertNotNull;
37 import static junit.framework.Assert.assertNull;
38 import static junit.framework.Assert.assertTrue;
39 import static junit.framework.Assert.fail;
40 
41 import android.accessibilityservice.AccessibilityService;
42 import android.app.ActivityManager;
43 import android.app.BroadcastOptions;
44 import android.app.ForegroundServiceStartNotAllowedException;
45 import android.app.Instrumentation;
46 import android.app.cts.android.app.cts.tools.WaitForBroadcast;
47 import android.app.cts.android.app.cts.tools.WatchUidRunner;
48 import android.app.stubs.CommandReceiver;
49 import android.app.stubs.LocalForegroundService;
50 import android.app.stubs.LocalForegroundServiceLocation;
51 import android.app.stubs.shared.NotificationHelper;
52 import android.app.stubs.shared.TestNotificationListener;
53 import android.content.ComponentName;
54 import android.content.Context;
55 import android.content.Intent;
56 import android.content.ServiceConnection;
57 import android.content.pm.ApplicationInfo;
58 import android.content.pm.ServiceInfo;
59 import android.media.session.MediaController;
60 import android.media.session.MediaSessionManager;
61 import android.os.Bundle;
62 import android.os.IBinder;
63 import android.os.PowerExemptionManager;
64 import android.os.RemoteCallback;
65 import android.os.SystemClock;
66 import android.permission.cts.PermissionUtils;
67 import android.platform.test.annotations.AsbSecurityTest;
68 import android.platform.test.annotations.Presubmit;
69 import android.platform.test.annotations.RequiresFlagsDisabled;
70 import android.platform.test.annotations.RequiresFlagsEnabled;
71 import android.platform.test.flag.junit.CheckFlagsRule;
72 import android.platform.test.flag.junit.DeviceFlagsValueProvider;
73 import android.provider.DeviceConfig;
74 import android.provider.Settings;
75 import android.server.wm.settings.SettingsSession;
76 import android.util.Log;
77 
78 import androidx.test.InstrumentationRegistry;
79 import androidx.test.ext.junit.runners.AndroidJUnit4;
80 import androidx.test.filters.LargeTest;
81 import androidx.test.uiautomator.UiDevice;
82 
83 import com.android.compatibility.common.util.SystemUtil;
84 import com.android.server.am.Flags;
85 
86 import org.junit.After;
87 import org.junit.Before;
88 import org.junit.Ignore;
89 import org.junit.Rule;
90 import org.junit.Test;
91 import org.junit.runner.RunWith;
92 
93 import java.util.List;
94 import java.util.concurrent.CountDownLatch;
95 import java.util.concurrent.TimeUnit;
96 
97 @RunWith(AndroidJUnit4.class)
98 public class ActivityManagerFgsBgStartTest {
99     private static final String TAG = ActivityManagerFgsBgStartTest.class.getName();
100 
101     static final String STUB_PACKAGE_NAME = "android.app.stubs";
102     static final String PACKAGE_NAME_APP1 = "com.android.app1";
103     static final String PACKAGE_NAME_APP2 = "com.android.app2";
104     static final String PACKAGE_NAME_APP3 = "com.android.app3";
105 
106     private static final String KEY_DEFAULT_FGS_STARTS_RESTRICTION_ENABLED =
107             "default_fgs_starts_restriction_enabled";
108 
109     private static final String KEY_FGS_START_FOREGROUND_TIMEOUT =
110             "fgs_start_foreground_timeout";
111 
112     private static final String KEY_PUSH_MESSAGING_OVER_QUOTA_BEHAVIOR =
113             "push_messaging_over_quota_behavior";
114 
115     // REASON_ALARM_MANAGER_ALARM_CLOCK is not exposed by PowerExemptionManager, hard code its value
116     // here.
117     private static final int REASON_ALARM_MANAGER_ALARM_CLOCK = 301;
118     private static final int DEFAULT_FGS_START_FOREGROUND_TIMEOUT_MS = 10 * 1000;
119 
120     public static final Integer LOCAL_SERVICE_PROCESS_CAPABILITY = new Integer(
121             PROCESS_CAPABILITY_FOREGROUND_CAMERA
122                     | PROCESS_CAPABILITY_FOREGROUND_MICROPHONE
123                     | PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK
124                     | PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK);
125 
126     private static final int PROCESS_CAPABILITY_ALL = PROCESS_CAPABILITY_FOREGROUND_LOCATION
127             | PROCESS_CAPABILITY_FOREGROUND_CAMERA
128             | PROCESS_CAPABILITY_FOREGROUND_MICROPHONE
129             | PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK
130             | PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK;
131 
132     static final int WAITFOR_MSEC = 10000;
133 
134     private static final int TEMP_ALLOWLIST_DURATION_MS = 2000;
135 
136     private static final String[] PACKAGE_NAMES = {
137             PACKAGE_NAME_APP1, PACKAGE_NAME_APP2, PACKAGE_NAME_APP3
138     };
139 
140     private Context mContext;
141     private Instrumentation mInstrumentation;
142     private Context mTargetContext;
143 
144     private int mOrigDeviceDemoMode = 0;
145     private boolean mOrigFgsTypeStartPermissionEnforcement;
146 
147     @Rule
148     public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
149 
150     @Before
setUp()151     public void setUp() throws Exception {
152         mInstrumentation = InstrumentationRegistry.getInstrumentation();
153         mContext = mInstrumentation.getContext();
154         mTargetContext = mInstrumentation.getTargetContext();
155         for (int i = 0; i < PACKAGE_NAMES.length; ++i) {
156             CtsAppTestUtils.makeUidIdle(mInstrumentation, PACKAGE_NAMES[i]);
157             // The manifest file gives test app SYSTEM_ALERT_WINDOW permissions, which also exempt
158             // the app from BG-FGS-launch restriction. Remove SYSTEM_ALERT_WINDOW permission to test
159             // other BG-FGS-launch exemptions.
160             allowBgActivityStart(PACKAGE_NAMES[i], false);
161         }
162         mOrigFgsTypeStartPermissionEnforcement = toggleBgFgsTypeStartPermissionEnforcement(false);
163         CtsAppTestUtils.turnScreenOn(mInstrumentation, mContext);
164         cleanupResiduals();
165         enableFgsRestriction(true, true, null);
166         // Press home key to ensure stopAppSwitches is called so the grace period of
167         // the background start will be ignored if there's any.
168         UiDevice.getInstance(mInstrumentation).pressHome();
169     }
170 
171     @After
tearDown()172     public void tearDown() throws Exception {
173         for (int i = 0; i < PACKAGE_NAMES.length; ++i) {
174             CtsAppTestUtils.makeUidIdle(mInstrumentation, PACKAGE_NAMES[i]);
175             allowBgActivityStart(PACKAGE_NAMES[i], true);
176         }
177         toggleBgFgsTypeStartPermissionEnforcement(mOrigFgsTypeStartPermissionEnforcement);
178         cleanupResiduals();
179         enableFgsRestriction(true, true, null);
180         for (String packageName : PACKAGE_NAMES) {
181             resetFgsSawRestrictionEnabled(packageName);
182             resetFgsRestriction(packageName);
183         }
184     }
185 
cleanupResiduals()186     private void cleanupResiduals() {
187         // Stop all the packages to avoid residual impact
188         final ActivityManager am = mContext.getSystemService(ActivityManager.class);
189         for (int i = 0; i < PACKAGE_NAMES.length; i++) {
190             final String pkgName = PACKAGE_NAMES[i];
191             SystemUtil.runWithShellPermissionIdentity(() -> {
192                 am.forceStopPackage(pkgName);
193             });
194         }
195         // Make sure we are in Home screen
196         mInstrumentation.getUiAutomation().performGlobalAction(
197                 AccessibilityService.GLOBAL_ACTION_HOME);
198     }
199 
toggleBgFgsTypeStartPermissionEnforcement(Boolean enforce)200     static boolean toggleBgFgsTypeStartPermissionEnforcement(Boolean enforce) {
201         final String namespaceActivityManager = "activity_manager";
202         final String keygFgsTypeStartPermissionEnforcement = "fgs_type_fg_perm_enforcement_flag";
203         final boolean[] origValue = new boolean[1];
204 
205         SystemUtil.runWithShellPermissionIdentity(() -> {
206             origValue[0] = DeviceConfig.getBoolean(namespaceActivityManager,
207                     keygFgsTypeStartPermissionEnforcement, true);
208             DeviceConfig.setProperty(namespaceActivityManager,
209                     keygFgsTypeStartPermissionEnforcement, enforce.toString(), false);
210         });
211         return origValue[0];
212     }
213 
214     /**
215      * APP1 is in BG state, it can start FGSL, but it won't get location capability.
216      * APP1 is in TOP state, it gets location capability.
217      * @throws Exception
218      */
219     @Presubmit
220     @Test
testFgsLocationStartFromBG()221     public void testFgsLocationStartFromBG() throws Exception {
222         ApplicationInfo app1Info = mContext.getPackageManager().getApplicationInfo(
223                 PACKAGE_NAME_APP1, 0);
224         WatchUidRunner uid1Watcher = new WatchUidRunner(mInstrumentation, app1Info.uid,
225                 WAITFOR_MSEC, PROCESS_CAPABILITY_ALL);
226 
227         try {
228             WaitForBroadcast waiter = new WaitForBroadcast(mInstrumentation.getTargetContext());
229             waiter.prepare(ACTION_START_FGSL_RESULT);
230             // APP1 is in BG state, Start FGSL in APP1, it won't get location capability.
231             Bundle bundle = new Bundle();
232             bundle.putInt(LocalForegroundServiceLocation.EXTRA_FOREGROUND_SERVICE_TYPE,
233                     ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION
234                     | ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA
235                     | ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE);
236             final Bundle bundle2 = new Bundle();
237             bundle2.putInt(LocalForegroundServiceLocation.EXTRA_FOREGROUND_SERVICE_TYPE,
238                     ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA
239                     | ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE);
240             // start FGSL.
241             enableFgsRestriction(false, true, null);
242             CommandReceiver.sendCommand(mContext,
243                     CommandReceiver.COMMAND_START_FOREGROUND_SERVICE_LOCATION,
244                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, bundle);
245             // APP1 is in FGS state, but won't get location capability.
246             uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE,
247                     WatchUidRunner.STATE_FG_SERVICE,
248                     new Integer(PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK
249                     | PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK));
250             waiter.doWait(WAITFOR_MSEC);
251             // stop FGSL
252             CommandReceiver.sendCommand(mContext,
253                     CommandReceiver.COMMAND_STOP_FOREGROUND_SERVICE_LOCATION,
254                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
255             uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE,
256                     WatchUidRunner.STATE_CACHED_EMPTY,
257                     new Integer(PROCESS_CAPABILITY_NONE));
258 
259             waiter = new WaitForBroadcast(mInstrumentation.getTargetContext());
260             waiter.prepare(ACTION_START_FGS_RESULT);
261             // APP1 is in FGS state,
262             CommandReceiver.sendCommand(mContext,
263                     CommandReceiver.COMMAND_START_FOREGROUND_SERVICE,
264                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, bundle2);
265             // start FGSL in app1, it won't get location capability.
266             CommandReceiver.sendCommand(mContext,
267                     CommandReceiver.COMMAND_START_FOREGROUND_SERVICE_LOCATION,
268                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, bundle);
269             // APP1 is in STATE_FG_SERVICE, but won't get location capability.
270             uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE,
271                     WatchUidRunner.STATE_FG_SERVICE,
272                     new Integer(PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK
273                     | PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK));
274             waiter.doWait(WAITFOR_MSEC);
275             // stop FGS.
276             CommandReceiver.sendCommand(mContext,
277                     CommandReceiver.COMMAND_STOP_FOREGROUND_SERVICE,
278                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
279             // stop FGSL.
280             CommandReceiver.sendCommand(mContext,
281                     CommandReceiver.COMMAND_STOP_FOREGROUND_SERVICE_LOCATION,
282                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
283 
284             // Put APP1 in TOP state, now it gets location capability (because the TOP process
285             // gets all while-in-use permission (not from FGSL).
286             allowBgActivityStart(PACKAGE_NAME_APP1, true);
287             CommandReceiver.sendCommand(mContext,
288                     CommandReceiver.COMMAND_START_ACTIVITY,
289                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
290             uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE,
291                     WatchUidRunner.STATE_TOP,
292                     new Integer(PROCESS_CAPABILITY_ALL));
293 
294             waiter = new WaitForBroadcast(mInstrumentation.getTargetContext());
295             waiter.prepare(ACTION_START_FGSL_RESULT);
296             // APP1 is in TOP state, start the FGSL in APP1, it will get location capability.
297             CommandReceiver.sendCommand(mContext,
298                     CommandReceiver.COMMAND_START_FOREGROUND_SERVICE_LOCATION,
299                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, bundle);
300             // Stop the activity.
301             CommandReceiver.sendCommand(mContext,
302                     CommandReceiver.COMMAND_STOP_ACTIVITY,
303                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
304             // The FGSL still has location capability because it is started from TOP.
305             uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE,
306                     WatchUidRunner.STATE_FG_SERVICE,
307                     new Integer(PROCESS_CAPABILITY_ALL));
308             waiter.doWait(WAITFOR_MSEC);
309             // Stop FGSL.
310             CommandReceiver.sendCommand(mContext,
311                     CommandReceiver.COMMAND_STOP_FOREGROUND_SERVICE_LOCATION,
312                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
313             uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE,
314                     WatchUidRunner.STATE_CACHED_EMPTY,
315                     new Integer(PROCESS_CAPABILITY_NONE));
316         } finally {
317             uid1Watcher.finish();
318         }
319     }
320 
321     /**
322      * APP1 is in BG state, it can start FGSL in APP2, but the FGS won't get location
323      * capability.
324      * APP1 is in TOP state, it can start FGSL in APP2, FGSL gets location capability.
325      * @throws Exception
326      */
327     @Presubmit
328     @Test
testFgsLocationStartFromBGTwoProcesses()329     public void testFgsLocationStartFromBGTwoProcesses() throws Exception {
330         ApplicationInfo app1Info = mContext.getPackageManager().getApplicationInfo(
331                 PACKAGE_NAME_APP1, 0);
332         ApplicationInfo app2Info = mContext.getPackageManager().getApplicationInfo(
333                 PACKAGE_NAME_APP2, 0);
334         WatchUidRunner uid1Watcher = new WatchUidRunner(mInstrumentation, app1Info.uid,
335                 WAITFOR_MSEC, PROCESS_CAPABILITY_ALL);
336         WatchUidRunner uid2Watcher = new WatchUidRunner(mInstrumentation, app2Info.uid,
337                 WAITFOR_MSEC, PROCESS_CAPABILITY_ALL);
338 
339         try {
340             // APP1 is in BG state, start FGSL in APP2.
341             Bundle bundle = new Bundle();
342             bundle.putInt(LocalForegroundServiceLocation.EXTRA_FOREGROUND_SERVICE_TYPE,
343                     ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION
344                     | ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA
345                     | ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE);
346             WaitForBroadcast waiter = new WaitForBroadcast(mInstrumentation.getTargetContext());
347             waiter.prepare(ACTION_START_FGSL_RESULT);
348             enableFgsRestriction(false, true, null);
349             CommandReceiver.sendCommand(mContext,
350                     CommandReceiver.COMMAND_START_FOREGROUND_SERVICE_LOCATION,
351                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP2, 0, bundle);
352             // APP2 won't have location capability because APP1 is not in TOP state.
353             uid2Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE,
354                     WatchUidRunner.STATE_FG_SERVICE,
355                     new Integer(PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK
356                     | PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK));
357             waiter.doWait(WAITFOR_MSEC);
358 
359             CommandReceiver.sendCommand(mContext,
360                     CommandReceiver.COMMAND_STOP_FOREGROUND_SERVICE_LOCATION,
361                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP2, 0, null);
362             uid2Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE,
363                     WatchUidRunner.STATE_CACHED_EMPTY,
364                     new Integer(PROCESS_CAPABILITY_NONE));
365 
366             // Put APP1 in TOP state
367             allowBgActivityStart(PACKAGE_NAME_APP1, true);
368             CommandReceiver.sendCommand(mContext,
369                     CommandReceiver.COMMAND_START_ACTIVITY,
370                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
371             uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE,
372                     WatchUidRunner.STATE_TOP,
373                     new Integer(PROCESS_CAPABILITY_ALL));
374 
375             waiter = new WaitForBroadcast(mInstrumentation.getTargetContext());
376             waiter.prepare(ACTION_START_FGSL_RESULT);
377             // From APP1, start FGSL in APP2.
378             CommandReceiver.sendCommand(mContext,
379                     CommandReceiver.COMMAND_START_FOREGROUND_SERVICE_LOCATION,
380                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP2, 0, bundle);
381             // Now APP2 gets location capability.
382             uid2Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE,
383                     WatchUidRunner.STATE_FG_SERVICE,
384                     new Integer(PROCESS_CAPABILITY_ALL));
385             waiter.doWait(WAITFOR_MSEC);
386 
387             CommandReceiver.sendCommand(mContext,
388                     CommandReceiver.COMMAND_STOP_FOREGROUND_SERVICE_LOCATION,
389                     PACKAGE_NAME_APP2, PACKAGE_NAME_APP2, 0, null);
390 
391             uid2Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE,
392                     WatchUidRunner.STATE_CACHED_EMPTY,
393                     new Integer(PROCESS_CAPABILITY_NONE));
394 
395             CommandReceiver.sendCommand(mContext,
396                     CommandReceiver.COMMAND_STOP_ACTIVITY,
397                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
398 
399             uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE,
400                     WatchUidRunner.STATE_CACHED_EMPTY,
401                     new Integer(PROCESS_CAPABILITY_NONE));
402         } finally {
403             uid1Watcher.finish();
404             uid2Watcher.finish();
405         }
406     }
407 
408     /**
409      * APP1 is in BG state, by a PendingIntent, it can start FGSL in APP2,
410      * but the FGS won't get location capability.
411      * APP1 is in TOP state, by a PendingIntent, it can start FGSL in APP2,
412      * FGSL gets location capability.
413      * @throws Exception
414      */
415     @Presubmit
416     @Test
testFgsLocationPendingIntent()417     public void testFgsLocationPendingIntent() throws Exception {
418         ApplicationInfo app1Info = mContext.getPackageManager().getApplicationInfo(
419                 PACKAGE_NAME_APP1, 0);
420         ApplicationInfo app2Info = mContext.getPackageManager().getApplicationInfo(
421                 PACKAGE_NAME_APP2, 0);
422         WatchUidRunner uid1Watcher = new WatchUidRunner(mInstrumentation, app1Info.uid,
423                 WAITFOR_MSEC, PROCESS_CAPABILITY_ALL);
424         WatchUidRunner uid2Watcher = new WatchUidRunner(mInstrumentation, app2Info.uid,
425                 WAITFOR_MSEC, PROCESS_CAPABILITY_ALL);
426 
427         try {
428             WaitForBroadcast waiter = new WaitForBroadcast(mInstrumentation.getTargetContext());
429             waiter.prepare(ACTION_START_FGSL_RESULT);
430             // APP1 is in BG state, start FGSL in APP2.
431             enableFgsRestriction(false, true, null);
432             CommandReceiver.sendCommand(mContext,
433                     CommandReceiver.COMMAND_CREATE_FGSL_PENDING_INTENT,
434                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP2, 0, null);
435             CommandReceiver.sendCommand(mContext,
436                     CommandReceiver.COMMAND_SEND_FGSL_PENDING_INTENT,
437                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP2, 0, null);
438             // APP2 won't have location capability.
439             uid2Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE,
440                     WatchUidRunner.STATE_FG_SERVICE,
441                     new Integer(PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK
442                     | PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK));
443             waiter.doWait(WAITFOR_MSEC);
444             // Stop FGSL in APP2.
445             CommandReceiver.sendCommand(mContext,
446                     CommandReceiver.COMMAND_STOP_FOREGROUND_SERVICE_LOCATION,
447                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP2, 0, null);
448             uid2Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE,
449                     WatchUidRunner.STATE_CACHED_EMPTY,
450                     new Integer(PROCESS_CAPABILITY_NONE));
451 
452             waiter = new WaitForBroadcast(mInstrumentation.getTargetContext());
453             waiter.prepare(ACTION_START_FGS_RESULT);
454             // Put APP1 in FGS state, start FGSL in APP2.
455             CommandReceiver.sendCommand(mContext,
456                     CommandReceiver.COMMAND_START_FOREGROUND_SERVICE,
457                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
458             uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE,
459                     WatchUidRunner.STATE_FG_SERVICE,
460                     new Integer(PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK
461                     | PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK));
462             waiter.doWait(WAITFOR_MSEC);
463             CommandReceiver.sendCommand(mContext,
464                     CommandReceiver.COMMAND_CREATE_FGSL_PENDING_INTENT,
465                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP2, 0, null);
466 
467             waiter = new WaitForBroadcast(mInstrumentation.getTargetContext());
468             waiter.prepare(ACTION_START_FGSL_RESULT);
469             CommandReceiver.sendCommand(mContext,
470                     CommandReceiver.COMMAND_SEND_FGSL_PENDING_INTENT,
471                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP2, 0, null);
472             // APP2 won't have location capability.
473             uid2Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE,
474                     WatchUidRunner.STATE_FG_SERVICE,
475                     new Integer(PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK
476                     | PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK));
477             waiter.doWait(WAITFOR_MSEC);
478             // stop FGSL in APP2.
479             CommandReceiver.sendCommand(mContext,
480                     CommandReceiver.COMMAND_STOP_FOREGROUND_SERVICE_LOCATION,
481                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP2, 0, null);
482             uid2Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE,
483                     WatchUidRunner.STATE_CACHED_EMPTY,
484                     new Integer(PROCESS_CAPABILITY_NONE));
485 
486             // put APP1 in TOP state, start FGSL in APP2.
487             allowBgActivityStart(PACKAGE_NAME_APP1, true);
488             CommandReceiver.sendCommand(mContext,
489                     CommandReceiver.COMMAND_START_ACTIVITY,
490                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
491             uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE,
492                     WatchUidRunner.STATE_TOP,
493                     new Integer(PROCESS_CAPABILITY_ALL));
494             CommandReceiver.sendCommand(mContext,
495                     CommandReceiver.COMMAND_CREATE_FGSL_PENDING_INTENT,
496                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP2, 0, null);
497 
498             waiter = new WaitForBroadcast(mInstrumentation.getTargetContext());
499             waiter.prepare(ACTION_START_FGSL_RESULT);
500             CommandReceiver.sendCommand(mContext,
501                     CommandReceiver.COMMAND_SEND_FGSL_PENDING_INTENT,
502                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP2, 0, null);
503             // APP2 now have location capability (because APP1 is TOP)
504             uid2Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE,
505                     WatchUidRunner.STATE_FG_SERVICE,
506                     new Integer(PROCESS_CAPABILITY_ALL));
507             waiter.doWait(WAITFOR_MSEC);
508 
509             // stop FGSL in APP2.
510             CommandReceiver.sendCommand(mContext,
511                     CommandReceiver.COMMAND_STOP_FOREGROUND_SERVICE_LOCATION,
512                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP2, 0, null);
513             uid2Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE,
514                     WatchUidRunner.STATE_CACHED_EMPTY,
515                     new Integer(PROCESS_CAPABILITY_NONE));
516 
517             // stop FGS in APP1,
518             CommandReceiver.sendCommand(mContext,
519                     CommandReceiver.COMMAND_STOP_FOREGROUND_SERVICE,
520                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
521             // stop TOP activity in APP1.
522             CommandReceiver.sendCommand(mContext,
523                     CommandReceiver.COMMAND_STOP_ACTIVITY,
524                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
525             uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE,
526                     WatchUidRunner.STATE_CACHED_EMPTY,
527                     new Integer(PROCESS_CAPABILITY_NONE));
528         } finally {
529             uid1Watcher.finish();
530             uid2Watcher.finish();
531         }
532     }
533 
534     /**
535      * Test a FGS start by bind from BG does not get get while-in-use capability.
536      * @throws Exception
537      */
538     @Presubmit
539     @Test
540     @AsbSecurityTest(cveBugId = 173516292)
testFgsLocationStartFromBGWithBind()541     public void testFgsLocationStartFromBGWithBind() throws Exception {
542         ApplicationInfo app1Info = mContext.getPackageManager().getApplicationInfo(
543                 PACKAGE_NAME_APP1, 0);
544         WatchUidRunner uid1Watcher = new WatchUidRunner(mInstrumentation, app1Info.uid,
545                 WAITFOR_MSEC, PROCESS_CAPABILITY_ALL);
546 
547         try {
548             WaitForBroadcast waiter = new WaitForBroadcast(mInstrumentation.getTargetContext());
549             waiter.prepare(ACTION_START_FGSL_RESULT);
550             // APP1 is in BG state, bind FGSL in APP1 first.
551             enableFgsRestriction(false, true, null);
552             CommandReceiver.sendCommand(mContext, CommandReceiver.COMMAND_BIND_FOREGROUND_SERVICE,
553                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
554             Bundle bundle = new Bundle();
555             bundle.putInt(LocalForegroundServiceLocation.EXTRA_FOREGROUND_SERVICE_TYPE,
556                     ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION
557                     | ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA
558                     | ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE);
559             // Then start FGSL in APP1, it won't get location capability.
560             CommandReceiver.sendCommand(mContext,
561                     CommandReceiver.COMMAND_START_FOREGROUND_SERVICE_LOCATION,
562                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, bundle);
563 
564             // APP1 is in FGS state, but won't get location capability.
565             uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE,
566                     WatchUidRunner.STATE_FG_SERVICE,
567                     new Integer(PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK
568                     | PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK));
569             waiter.doWait(WAITFOR_MSEC);
570 
571             // unbind service.
572             CommandReceiver.sendCommand(mContext, CommandReceiver.COMMAND_UNBIND_SERVICE,
573                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
574             // stop FGSL
575             CommandReceiver.sendCommand(mContext,
576                     CommandReceiver.COMMAND_STOP_FOREGROUND_SERVICE_LOCATION,
577                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
578             uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE,
579                     WatchUidRunner.STATE_CACHED_EMPTY,
580                     new Integer(PROCESS_CAPABILITY_NONE));
581         } finally {
582             uid1Watcher.finish();
583         }
584     }
585 
586     @Presubmit
587     @Test
testUpdateUidProcState()588     public void testUpdateUidProcState() throws Exception {
589         ApplicationInfo app1Info = mContext.getPackageManager().getApplicationInfo(
590                 PACKAGE_NAME_APP1, 0);
591         WatchUidRunner uid1Watcher = new WatchUidRunner(mInstrumentation, app1Info.uid,
592                 WAITFOR_MSEC);
593         ApplicationInfo app2Info = mContext.getPackageManager().getApplicationInfo(
594                 PACKAGE_NAME_APP2, 0);
595         WatchUidRunner uid2Watcher = new WatchUidRunner(mInstrumentation, app2Info.uid,
596                 WAITFOR_MSEC);
597         ApplicationInfo app3Info = mContext.getPackageManager().getApplicationInfo(
598                 PACKAGE_NAME_APP3, 0);
599         WatchUidRunner uid3Watcher = new WatchUidRunner(mInstrumentation, app3Info.uid,
600                 WAITFOR_MSEC);
601 
602         try {
603             WaitForBroadcast waiter = new WaitForBroadcast(mInstrumentation.getTargetContext());
604             waiter.prepare(ACTION_START_FGS_RESULT);
605 
606             enableFgsRestriction(false, true, null);
607 
608             // START FGS in APP2.
609             CommandReceiver.sendCommand(mContext,
610                     CommandReceiver.COMMAND_START_FOREGROUND_SERVICE,
611                     PACKAGE_NAME_APP2, PACKAGE_NAME_APP2, 0, null);
612             // APP2 proc state is 4.
613             uid2Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE,
614                     WatchUidRunner.STATE_FG_SERVICE);
615             waiter.doWait(WAITFOR_MSEC);
616 
617             // APP2 binds to APP1.
618             CommandReceiver.sendCommand(mContext, CommandReceiver.COMMAND_BIND_SERVICE,
619                     PACKAGE_NAME_APP2, PACKAGE_NAME_APP1, Context.BIND_INCLUDE_CAPABILITIES, null);
620             // APP1 gets proc state 4.
621             uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE,
622                     WatchUidRunner.STATE_FG_SERVICE);
623 
624             // Start activity in APP3, this put APP3 in TOP state.
625             allowBgActivityStart(PACKAGE_NAME_APP3, true);
626             CommandReceiver.sendCommand(mContext,
627                     CommandReceiver.COMMAND_START_ACTIVITY,
628                     PACKAGE_NAME_APP3, PACKAGE_NAME_APP3, 0, null);
629             // APP3 gets proc state 2.
630             uid3Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_TOP);
631 
632             // APP3 repeatedly bind/unbind with APP2, observer APP1 proc state change.
633             // Observe updateUidProcState() call latency.
634             for (int i = 0; i < 10; ++i) {
635                 // APP3 bind to APP2
636                 CommandReceiver.sendCommand(mContext,
637                         CommandReceiver.COMMAND_BIND_SERVICE,
638                         PACKAGE_NAME_APP3, PACKAGE_NAME_APP2, Context.BIND_INCLUDE_CAPABILITIES,
639                         null);
640                 uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_BOUND_TOP);
641 
642                 CommandReceiver.sendCommand(mContext, CommandReceiver.COMMAND_UNBIND_SERVICE,
643                         PACKAGE_NAME_APP3, PACKAGE_NAME_APP2, 0, null);
644                 uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_FG_SERVICE);
645             }
646 
647             // unbind service.
648             CommandReceiver.sendCommand(mContext, CommandReceiver.COMMAND_STOP_ACTIVITY,
649                     PACKAGE_NAME_APP3, PACKAGE_NAME_APP3, 0, null);
650             CommandReceiver.sendCommand(mContext, CommandReceiver.COMMAND_UNBIND_SERVICE,
651                     PACKAGE_NAME_APP3, PACKAGE_NAME_APP2, 0, null);
652             CommandReceiver.sendCommand(mContext, CommandReceiver.COMMAND_UNBIND_SERVICE,
653                     PACKAGE_NAME_APP2, PACKAGE_NAME_APP1, 0, null);
654             CommandReceiver.sendCommand(mContext,
655                     CommandReceiver.COMMAND_STOP_FOREGROUND_SERVICE,
656                     PACKAGE_NAME_APP2, PACKAGE_NAME_APP2, 0, null);
657 
658         } finally {
659             uid1Watcher.finish();
660             uid2Watcher.finish();
661             uid3Watcher.finish();
662             allowBgActivityStart(PACKAGE_NAME_APP3, false);
663         }
664     }
665 
666     /**
667      * Test FGS background startForeground() restriction, use DeviceConfig to turn on restriction.
668      * @throws Exception
669      */
670     @Presubmit
671     @Test
testFgsStartFromBG1()672     public void testFgsStartFromBG1() throws Exception {
673         testFgsStartFromBG(true);
674     }
675 
676     /**
677      * Test FGS background startForeground() restriction, use AppCompat CHANGE ID to turn on
678      * restriction.
679      * @throws Exception
680      */
681     @Presubmit
682     @Test
testFgsStartFromBG2()683     public void testFgsStartFromBG2() throws Exception {
684         testFgsStartFromBG(false);
685     }
686 
testFgsStartFromBG(boolean useDeviceConfig)687     private void testFgsStartFromBG(boolean useDeviceConfig) throws Exception {
688         ApplicationInfo app1Info = mContext.getPackageManager().getApplicationInfo(
689                 PACKAGE_NAME_APP1, 0);
690         WatchUidRunner uid1Watcher = new WatchUidRunner(mInstrumentation, app1Info.uid,
691                 WAITFOR_MSEC);
692         try {
693             WaitForBroadcast waiter = new WaitForBroadcast(mInstrumentation.getTargetContext());
694             waiter.prepare(ACTION_START_FGS_RESULT);
695             // disable the FGS background startForeground() restriction.
696             enableFgsRestriction(false, true, null);
697             enableFgsRestriction(false, useDeviceConfig, PACKAGE_NAME_APP1);
698             // APP1 is in BG state, Start FGS in APP1.
699             CommandReceiver.sendCommand(mContext,
700                     CommandReceiver.COMMAND_START_FOREGROUND_SERVICE,
701                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
702             // APP1 is in STATE_FG_SERVICE.
703             uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_FG_SERVICE);
704             waiter.doWait(WAITFOR_MSEC);
705             // stop FGS.
706             CommandReceiver.sendCommand(mContext,
707                     CommandReceiver.COMMAND_STOP_FOREGROUND_SERVICE,
708                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
709             uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_CACHED_EMPTY);
710 
711             // Enable the FGS background startForeground() restriction.
712             allowBgActivityStart(PACKAGE_NAME_APP1, false);
713             enableFgsRestriction(true, true, null);
714             enableFgsRestriction(true, useDeviceConfig, PACKAGE_NAME_APP1);
715             // Start FGS in BG state.
716             waiter = new WaitForBroadcast(mInstrumentation.getTargetContext());
717             waiter.prepare(ACTION_START_FGS_RESULT);
718             CommandReceiver.sendCommand(mContext,
719                     CommandReceiver.COMMAND_START_FOREGROUND_SERVICE,
720                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
721             // APP1 does not enter FGS state
722             try {
723                 waiter.doWait(WAITFOR_MSEC);
724                 fail("Service should not enter foreground service state");
725             } catch (Exception e) {
726             }
727 
728             // Put APP1 in TOP state.
729             allowBgActivityStart(PACKAGE_NAME_APP1, true);
730             CommandReceiver.sendCommand(mContext,
731                     CommandReceiver.COMMAND_START_ACTIVITY,
732                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
733             uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_TOP);
734             allowBgActivityStart(PACKAGE_NAME_APP1, false);
735 
736             waiter = new WaitForBroadcast(mInstrumentation.getTargetContext());
737             waiter.prepare(ACTION_START_FGS_RESULT);
738             // Now it can start FGS.
739             CommandReceiver.sendCommand(mContext,
740                     CommandReceiver.COMMAND_START_FOREGROUND_SERVICE,
741                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
742             // Stop activity.
743             CommandReceiver.sendCommand(mContext,
744                     CommandReceiver.COMMAND_STOP_ACTIVITY,
745                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
746             // FGS is still running.
747             uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_FG_SERVICE);
748             waiter.doWait(WAITFOR_MSEC);
749             // Stop the FGS.
750             CommandReceiver.sendCommand(mContext,
751                     CommandReceiver.COMMAND_STOP_FOREGROUND_SERVICE,
752                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
753             uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_CACHED_EMPTY);
754         } finally {
755             uid1Watcher.finish();
756         }
757     }
758 
759     /**
760      * Test a FGS can start from a process that is at BOUND_TOP state.
761      * @throws Exception
762      */
763     @Presubmit
764     @Test
testFgsStartFromBoundTopState()765     public void testFgsStartFromBoundTopState() throws Exception {
766         ApplicationInfo app1Info = mContext.getPackageManager().getApplicationInfo(
767                 PACKAGE_NAME_APP1, 0);
768         ApplicationInfo app2Info = mContext.getPackageManager().getApplicationInfo(
769                 PACKAGE_NAME_APP2, 0);
770         ApplicationInfo app3Info = mContext.getPackageManager().getApplicationInfo(
771                 PACKAGE_NAME_APP3, 0);
772         WatchUidRunner uid1Watcher = new WatchUidRunner(mInstrumentation, app1Info.uid,
773                 WAITFOR_MSEC);
774         WatchUidRunner uid2Watcher = new WatchUidRunner(mInstrumentation, app2Info.uid,
775                 WAITFOR_MSEC);
776         WatchUidRunner uid3Watcher = new WatchUidRunner(mInstrumentation, app3Info.uid,
777                 WAITFOR_MSEC);
778         try {
779             // Enable the FGS background startForeground() restriction.
780             enableFgsRestriction(true, true, null);
781 
782             // Put APP1 in TOP state.
783             allowBgActivityStart(PACKAGE_NAME_APP1, true);
784             CommandReceiver.sendCommand(mContext,
785                     CommandReceiver.COMMAND_START_ACTIVITY,
786                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
787             uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_TOP);
788 
789             // APP1 bound to service in APP2, APP2 get BOUND_TOP state.
790             CommandReceiver.sendCommand(mContext,
791                     CommandReceiver.COMMAND_BIND_SERVICE,
792                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP2, 0, null);
793             uid2Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_BOUND_TOP);
794 
795             WaitForBroadcast waiter = new WaitForBroadcast(mInstrumentation.getTargetContext());
796             waiter.prepare(ACTION_START_FGS_RESULT);
797             // APP2 can start FGS in APP3.
798             CommandReceiver.sendCommand(mContext,
799                     CommandReceiver.COMMAND_START_FOREGROUND_SERVICE,
800                     PACKAGE_NAME_APP2, PACKAGE_NAME_APP3, 0, null);
801             uid3Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_FG_SERVICE);
802             waiter.doWait(WAITFOR_MSEC);
803 
804             // Stop activity.
805             CommandReceiver.sendCommand(mContext,
806                     CommandReceiver.COMMAND_STOP_ACTIVITY,
807                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
808             uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_CACHED_EMPTY);
809             // unbind service.
810             CommandReceiver.sendCommand(mContext,
811                     CommandReceiver.COMMAND_UNBIND_SERVICE,
812                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP2, 0, null);
813             uid2Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_CACHED_EMPTY);
814             // Stop the FGS.
815             CommandReceiver.sendCommand(mContext,
816                     CommandReceiver.COMMAND_STOP_FOREGROUND_SERVICE,
817                     PACKAGE_NAME_APP2, PACKAGE_NAME_APP3, 0, null);
818             uid3Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_CACHED_EMPTY);
819         } finally {
820             uid1Watcher.finish();
821             uid2Watcher.finish();
822             uid3Watcher.finish();
823         }
824     }
825 
826     /**
827      * Test a FGS can start from a process that is at FOREGROUND_SERVICE state.
828      * @throws Exception
829      */
830     @Presubmit
831     @Test
testFgsStartFromFgsState()832     public void testFgsStartFromFgsState() throws Exception {
833         ApplicationInfo app1Info = mContext.getPackageManager().getApplicationInfo(
834                 PACKAGE_NAME_APP1, 0);
835         ApplicationInfo app2Info = mContext.getPackageManager().getApplicationInfo(
836                 PACKAGE_NAME_APP2, 0);
837         ApplicationInfo app3Info = mContext.getPackageManager().getApplicationInfo(
838                 PACKAGE_NAME_APP3, 0);
839         WatchUidRunner uid1Watcher = new WatchUidRunner(mInstrumentation, app1Info.uid,
840                 WAITFOR_MSEC);
841         WatchUidRunner uid2Watcher = new WatchUidRunner(mInstrumentation, app2Info.uid,
842                 WAITFOR_MSEC);
843         WatchUidRunner uid3Watcher = new WatchUidRunner(mInstrumentation, app3Info.uid,
844                 WAITFOR_MSEC);
845         try {
846             // Enable the FGS background startForeground() restriction.
847             enableFgsRestriction(true, true, null);
848 
849             // Put APP1 in TOP state.
850             allowBgActivityStart(PACKAGE_NAME_APP1, true);
851             CommandReceiver.sendCommand(mContext,
852                     CommandReceiver.COMMAND_START_ACTIVITY,
853                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
854             uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_TOP);
855 
856             WaitForBroadcast waiter = new WaitForBroadcast(mInstrumentation.getTargetContext());
857             waiter.prepare(ACTION_START_FGS_RESULT);
858             // APP1 can start FGS in APP2, APP2 gets FOREGROUND_SERVICE state.
859             CommandReceiver.sendCommand(mContext,
860                     CommandReceiver.COMMAND_START_FOREGROUND_SERVICE,
861                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP2, 0, null);
862             uid2Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_FG_SERVICE);
863             waiter.doWait(WAITFOR_MSEC);
864 
865             waiter = new WaitForBroadcast(mInstrumentation.getTargetContext());
866             waiter.prepare(ACTION_START_FGS_RESULT);
867             // APP2 can start FGS in APP3.
868             CommandReceiver.sendCommand(mContext,
869                     CommandReceiver.COMMAND_START_FOREGROUND_SERVICE,
870                     PACKAGE_NAME_APP2, PACKAGE_NAME_APP3, 0, null);
871             uid3Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_FG_SERVICE);
872             waiter.doWait(WAITFOR_MSEC);
873 
874             // Stop activity in APP1.
875             CommandReceiver.sendCommand(mContext,
876                     CommandReceiver.COMMAND_STOP_ACTIVITY,
877                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
878             uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_CACHED_EMPTY);
879             // Stop FGS in APP2.
880             CommandReceiver.sendCommand(mContext,
881                     CommandReceiver.COMMAND_STOP_FOREGROUND_SERVICE,
882                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP2, 0, null);
883             uid2Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_CACHED_EMPTY);
884             // Stop FGS in APP3.
885             CommandReceiver.sendCommand(mContext,
886                     CommandReceiver.COMMAND_STOP_FOREGROUND_SERVICE,
887                     PACKAGE_NAME_APP3, PACKAGE_NAME_APP3, 0, null);
888             uid3Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_CACHED_EMPTY);
889         } finally {
890             uid1Watcher.finish();
891             uid2Watcher.finish();
892             uid3Watcher.finish();
893         }
894     }
895 
896     /**
897      * When the service is started by bindService() command, test when BG-FGS-launch
898      * restriction is disabled, FGS can start from background.
899      * @throws Exception
900      */
901     @Presubmit
902     @Test
testFgsStartFromBGWithBind()903     public void testFgsStartFromBGWithBind() throws Exception {
904         ApplicationInfo app1Info = mContext.getPackageManager().getApplicationInfo(
905                 PACKAGE_NAME_APP1, 0);
906         WatchUidRunner uid1Watcher = new WatchUidRunner(mInstrumentation, app1Info.uid,
907                 WAITFOR_MSEC);
908 
909         try {
910             WaitForBroadcast waiter = new WaitForBroadcast(mInstrumentation.getTargetContext());
911             waiter.prepare(ACTION_START_FGSL_RESULT);
912             // APP1 is in BG state, bind FGSL in APP1 first.
913             CommandReceiver.sendCommand(mContext, CommandReceiver.COMMAND_BIND_FOREGROUND_SERVICE,
914                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
915             // Then start FGSL in APP1
916             enableFgsRestriction(false, true, null);
917             CommandReceiver.sendCommand(mContext,
918                     CommandReceiver.COMMAND_START_FOREGROUND_SERVICE_LOCATION,
919                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
920             // APP1 is in FGS state
921             uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_FG_SERVICE);
922             waiter.doWait(WAITFOR_MSEC);
923 
924             // stop FGS
925             CommandReceiver.sendCommand(mContext,
926                     CommandReceiver.COMMAND_STOP_FOREGROUND_SERVICE_LOCATION,
927                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
928             // unbind service.
929             CommandReceiver.sendCommand(mContext, CommandReceiver.COMMAND_UNBIND_SERVICE,
930                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
931             uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_CACHED_EMPTY);
932         } finally {
933             uid1Watcher.finish();
934         }
935     }
936 
937     /**
938      * When the service is started by bindService() command, test when BG-FGS-launch
939      * restriction is enabled, FGS can NOT start from background.
940      * @throws Exception
941      */
942     @Presubmit
943     @Test
testFgsStartFromBGWithBindWithRestriction()944     public void testFgsStartFromBGWithBindWithRestriction() throws Exception {
945         ApplicationInfo app1Info = mContext.getPackageManager().getApplicationInfo(
946                 PACKAGE_NAME_APP1, 0);
947         WatchUidRunner uid1Watcher = new WatchUidRunner(mInstrumentation, app1Info.uid,
948                 WAITFOR_MSEC);
949 
950         try {
951             enableFgsRestriction(true, true, null);
952             // APP1 is in BG state, bind FGSL in APP1 first.
953             CommandReceiver.sendCommand(mContext, CommandReceiver.COMMAND_BIND_FOREGROUND_SERVICE,
954                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
955             // Then start FGS in APP1
956             WaitForBroadcast waiter = new WaitForBroadcast(mInstrumentation.getTargetContext());
957             waiter.prepare(ACTION_START_FGS_RESULT);
958             CommandReceiver.sendCommand(mContext,
959                     CommandReceiver.COMMAND_START_FOREGROUND_SERVICE,
960                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
961             // APP1 does not enter FGS state
962             try {
963                 waiter.doWait(WAITFOR_MSEC);
964                 fail("Service should not enter foreground service state");
965             } catch (Exception e) {
966             }
967 
968             // stop FGS
969             CommandReceiver.sendCommand(mContext,
970                     CommandReceiver.COMMAND_STOP_FOREGROUND_SERVICE,
971                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
972             // unbind service.
973             CommandReceiver.sendCommand(mContext, CommandReceiver.COMMAND_UNBIND_SERVICE,
974                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
975             uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_CACHED_EMPTY);
976         } finally {
977             uid1Watcher.finish();
978         }
979     }
980 
981     /**
982      * Test BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS flag.
983      * Shell has START_ACTIVITIES_FROM_BACKGROUND permission, it can use this bind flag to
984      * pass BG-Activity-launch ability to APP2, then APP2 can start APP2 FGS from background.
985      */
986     @Presubmit
987     @Test
testFgsBindingFlagActivity()988     public void testFgsBindingFlagActivity() throws Exception {
989         testFgsBindingFlag(Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS);
990     }
991 
992     /**
993      * Test BIND_ALLOW_FOREGROUND_SERVICE_STARTS_FROM_BACKGROUND flag.
994      * Shell has START_FOREGROUND_SERVICES_FROM_BACKGROUND permission, it can use this bind flag to
995      * pass BG-FGS-launch ability to APP2, then APP2 can start APP3 FGS from background.
996      */
997     @Presubmit
998     @Test
testFgsBindingFlagFGS()999     public void testFgsBindingFlagFGS() throws Exception {
1000         testFgsBindingFlag(Context.BIND_ALLOW_FOREGROUND_SERVICE_STARTS_FROM_BACKGROUND);
1001     }
1002 
1003     /**
1004      * Test no binding flag.
1005      * Shell has START_FOREGROUND_SERVICES_FROM_BACKGROUND permission, without any bind flag,
1006      * the BG-FGS-launch ability can be passed to APP2 by service binding, then APP2 can start
1007      * APP3 FGS from background.
1008      */
1009     @Presubmit
1010     @Test
testFgsBindingFlagNone()1011     public void testFgsBindingFlagNone() throws Exception {
1012         testFgsBindingFlag(0);
1013     }
1014 
testFgsBindingFlag(int bindingFlag)1015     private void testFgsBindingFlag(int bindingFlag) throws Exception {
1016         ApplicationInfo app1Info = mContext.getPackageManager().getApplicationInfo(
1017                 PACKAGE_NAME_APP1, 0);
1018         ApplicationInfo app2Info = mContext.getPackageManager().getApplicationInfo(
1019                 PACKAGE_NAME_APP2, 0);
1020         ApplicationInfo app3Info = mContext.getPackageManager().getApplicationInfo(
1021                 PACKAGE_NAME_APP3, 0);
1022         WatchUidRunner uid1Watcher = new WatchUidRunner(mInstrumentation, app1Info.uid,
1023                 WAITFOR_MSEC);
1024         WatchUidRunner uid2Watcher = new WatchUidRunner(mInstrumentation, app2Info.uid,
1025                 WAITFOR_MSEC);
1026         WatchUidRunner uid3Watcher = new WatchUidRunner(mInstrumentation, app3Info.uid,
1027                 WAITFOR_MSEC);
1028         try {
1029             // Enable the FGS background startForeground() restriction.
1030             enableFgsRestriction(true, true, null);
1031 
1032             // testapp is in background.
1033             // testapp binds to service in APP2, APP2 still in background state.
1034             final Intent intent = new Intent().setClassName(
1035                     PACKAGE_NAME_APP2, "android.app.stubs.LocalService");
1036 
1037             /*
1038             final ServiceConnection connection = new ServiceConnection() {
1039                 @Override
1040                 public void onServiceConnected(ComponentName name, IBinder service) {
1041                 }
1042                 @Override
1043                 public void onServiceDisconnected(ComponentName name) {
1044                 }
1045             };
1046             runWithShellPermissionIdentity(() -> {
1047                 mTargetContext.bindService(intent, connection,
1048                         Context.BIND_AUTO_CREATE | Context.BIND_WAIVE_PRIORITY);
1049             });
1050 
1051             // APP2 can not start FGS in APP3.
1052             WaitForBroadcast waiter = new WaitForBroadcast(mInstrumentation.getTargetContext());
1053             waiter.prepare(ACTION_START_FGS_RESULT);
1054             CommandReceiver.sendCommand(mContext,
1055                     CommandReceiver.COMMAND_START_FOREGROUND_SERVICE,
1056                     PACKAGE_NAME_APP2, PACKAGE_NAME_APP3, 0, null);
1057             try {
1058                 waiter.doWait(WAITFOR_MSEC);
1059                 fail("Service should not enter foreground service state");
1060             } catch (Exception e) {
1061             }
1062 
1063             // testapp unbind service in APP2.
1064             runWithShellPermissionIdentity(() -> mTargetContext.unbindService(connection));
1065             uid2Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_CACHED_EMPTY);
1066             */
1067 
1068             // testapp is in background.
1069             // testapp binds to service in APP2 using the binding flag.
1070             // APP2 still in background state.
1071             final ServiceConnection connection2 = new ServiceConnection() {
1072                 @Override
1073                 public void onServiceConnected(ComponentName name, IBinder service) {
1074                 }
1075                 @Override
1076                 public void onServiceDisconnected(ComponentName name) {
1077                 }
1078             };
1079             runWithShellPermissionIdentity(() -> mTargetContext.bindService(intent, connection2,
1080                     Context.BIND_AUTO_CREATE | Context.BIND_WAIVE_PRIORITY
1081                             | bindingFlag));
1082 
1083             WaitForBroadcast waiter = new WaitForBroadcast(mInstrumentation.getTargetContext());
1084             waiter.prepare(ACTION_START_FGS_RESULT);
1085             // Because the binding flag,
1086             // APP2 can start FGS from background.
1087             CommandReceiver.sendCommand(mContext,
1088                     CommandReceiver.COMMAND_START_FOREGROUND_SERVICE,
1089                     PACKAGE_NAME_APP2, PACKAGE_NAME_APP3, 0, null);
1090             uid3Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_FG_SERVICE);
1091             waiter.doWait(WAITFOR_MSEC);
1092 
1093             // testapp unbind service in APP2.
1094             runWithShellPermissionIdentity(() -> mTargetContext.unbindService(connection2));
1095             uid2Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_CACHED_EMPTY);
1096             // Stop the FGS in APP3.
1097             CommandReceiver.sendCommand(mContext,
1098                     CommandReceiver.COMMAND_STOP_FOREGROUND_SERVICE,
1099                     PACKAGE_NAME_APP3, PACKAGE_NAME_APP3, 0, null);
1100             uid3Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_CACHED_EMPTY);
1101         } finally {
1102             uid1Watcher.finish();
1103             uid2Watcher.finish();
1104             uid3Watcher.finish();
1105         }
1106     }
1107 
1108     /**
1109      * Test a FGS can start from BG if the app has SYSTEM_ALERT_WINDOW permission.
1110      */
1111     @Presubmit
1112     @Test
1113     @RequiresFlagsDisabled(Flags.FLAG_FGS_DISABLE_SAW)
testFgsStartSystemAlertWindow()1114     public void testFgsStartSystemAlertWindow() throws Exception {
1115         ApplicationInfo app1Info = mContext.getPackageManager().getApplicationInfo(
1116                 PACKAGE_NAME_APP1, 0);
1117         WatchUidRunner uid1Watcher = new WatchUidRunner(mInstrumentation, app1Info.uid,
1118                 WAITFOR_MSEC);
1119         try {
1120             // Enable the FGS background startForeground() restriction.
1121             enableFgsRestriction(true, true, null);
1122             for (String packageName : PACKAGE_NAMES) {
1123                 enableFgsSawRestriction(false, packageName);
1124             }
1125             // Start FGS in BG state.
1126             WaitForBroadcast waiter = new WaitForBroadcast(mInstrumentation.getTargetContext());
1127             waiter.prepare(ACTION_START_FGS_RESULT);
1128             CommandReceiver.sendCommand(mContext,
1129                     CommandReceiver.COMMAND_START_FOREGROUND_SERVICE,
1130                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
1131             // APP1 does not enter FGS state
1132             try {
1133                 waiter.doWait(WAITFOR_MSEC);
1134                 fail("Service should not enter foreground service state");
1135             } catch (Exception e) {
1136             }
1137 
1138             PermissionUtils.grantPermission(
1139                     PACKAGE_NAME_APP1, android.Manifest.permission.SYSTEM_ALERT_WINDOW);
1140             waiter = new WaitForBroadcast(mInstrumentation.getTargetContext());
1141             waiter.prepare(ACTION_START_FGS_RESULT);
1142             // Now it can start FGS.
1143             CommandReceiver.sendCommand(mContext,
1144                     CommandReceiver.COMMAND_START_FOREGROUND_SERVICE,
1145                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
1146             uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_FG_SERVICE);
1147             waiter.doWait(WAITFOR_MSEC);
1148             // Stop the FGS.
1149             CommandReceiver.sendCommand(mContext,
1150                     CommandReceiver.COMMAND_STOP_FOREGROUND_SERVICE,
1151                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
1152             uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_CACHED_EMPTY);
1153         } finally {
1154             uid1Watcher.finish();
1155         }
1156     }
1157 
1158     @Test
1159     @RequiresFlagsEnabled(Flags.FLAG_FGS_DISABLE_SAW)
testFgsStartSystemAlertWindowDisabled()1160     public void testFgsStartSystemAlertWindowDisabled() throws Exception {
1161         ApplicationInfo app1Info = mContext.getPackageManager().getApplicationInfo(
1162                 PACKAGE_NAME_APP1, 0);
1163         WatchUidRunner uid1Watcher = new WatchUidRunner(mInstrumentation, app1Info.uid,
1164                 WAITFOR_MSEC);
1165         try {
1166             // Enable the FGS background startForeground() restriction.
1167             enableFgsRestriction(true, true, null);
1168             for (String packageName : PACKAGE_NAMES) {
1169                 enableFgsSawRestriction(true, packageName);
1170             }
1171             // Start FGS in BG state.
1172             WaitForBroadcast waiter = new WaitForBroadcast(mInstrumentation.getTargetContext());
1173             waiter.prepare(ACTION_START_FGS_RESULT);
1174             CommandReceiver.sendCommand(mContext,
1175                     CommandReceiver.COMMAND_START_FOREGROUND_SERVICE,
1176                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
1177             // APP1 does not enter FGS state
1178             try {
1179                 waiter.doWait(WAITFOR_MSEC);
1180                 fail("Service should not enter foreground service state");
1181             } catch (Exception e) {
1182             }
1183 
1184             PermissionUtils.grantPermission(
1185                     PACKAGE_NAME_APP1, android.Manifest.permission.SYSTEM_ALERT_WINDOW);
1186             waiter = new WaitForBroadcast(mInstrumentation.getTargetContext());
1187             waiter.prepare(ACTION_START_FGS_RESULT);
1188             // It should still fail
1189             CommandReceiver.sendCommand(mContext,
1190                     CommandReceiver.COMMAND_START_FOREGROUND_SERVICE,
1191                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
1192             // STOPSHIP(b/296558535): Update to test with a system alert overlay
1193             try {
1194                 waiter.doWait(WAITFOR_MSEC);
1195                 fail("Service should not enter foreground service state");
1196             } catch (Exception e) {
1197             }
1198         } finally {
1199             uid1Watcher.finish();
1200         }
1201     }
1202 
1203     /**
1204      * Test a FGS can start from BG if the device is in retail demo mode.
1205      */
1206     @Presubmit
1207     @Test
1208     // Change Settings.Global.DEVICE_DEMO_MODE on device may trigger other listener and put
1209     // the device in undesired state, for example, the battery charge level is set to 35%
1210     // permanently, ignore this test for now.
1211     @Ignore
testFgsStartRetailDemoMode()1212     public void testFgsStartRetailDemoMode() throws Exception {
1213         ApplicationInfo app1Info = mContext.getPackageManager().getApplicationInfo(
1214                 PACKAGE_NAME_APP1, 0);
1215         WatchUidRunner uid1Watcher = new WatchUidRunner(mInstrumentation, app1Info.uid,
1216                 WAITFOR_MSEC);
1217         runWithShellPermissionIdentity(()-> {
1218             mOrigDeviceDemoMode = Settings.Global.getInt(mContext.getContentResolver(),
1219                     Settings.Global.DEVICE_DEMO_MODE, 0); });
1220 
1221         try {
1222             // Enable the FGS background startForeground() restriction.
1223             enableFgsRestriction(true, true, null);
1224             // Start FGS in BG state.
1225             WaitForBroadcast waiter = new WaitForBroadcast(mInstrumentation.getTargetContext());
1226             waiter.prepare(ACTION_START_FGS_RESULT);
1227             CommandReceiver.sendCommand(mContext,
1228                     CommandReceiver.COMMAND_START_FOREGROUND_SERVICE,
1229                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
1230             // APP1 does not enter FGS state
1231             try {
1232                 waiter.doWait(WAITFOR_MSEC);
1233                 fail("Service should not enter foreground service state");
1234             } catch (Exception e) {
1235             }
1236 
1237             runWithShellPermissionIdentity(()-> {
1238                 Settings.Global.putInt(mContext.getContentResolver(),
1239                         Settings.Global.DEVICE_DEMO_MODE, 1); });
1240             waiter = new WaitForBroadcast(mInstrumentation.getTargetContext());
1241             waiter.prepare(ACTION_START_FGS_RESULT);
1242             // Now it can start FGS.
1243             CommandReceiver.sendCommand(mContext,
1244                     CommandReceiver.COMMAND_START_FOREGROUND_SERVICE,
1245                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
1246             uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_FG_SERVICE);
1247             waiter.doWait(WAITFOR_MSEC);
1248             // Stop the FGS.
1249             CommandReceiver.sendCommand(mContext,
1250                     CommandReceiver.COMMAND_STOP_FOREGROUND_SERVICE,
1251                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
1252             uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_CACHED_EMPTY);
1253         } finally {
1254             uid1Watcher.finish();
1255             runWithShellPermissionIdentity(()-> {
1256                 Settings.Global.putInt(mContext.getContentResolver(),
1257                         Settings.Global.DEVICE_DEMO_MODE, mOrigDeviceDemoMode); });
1258         }
1259     }
1260 
1261     // At Context.startForegroundService() or Service.startForeground() calls, if the FGS is
1262     // restricted by background restriction and the app's targetSdkVersion is at least S, the
1263     // framework throws a ForegroundServiceStartNotAllowedException with error message.
1264     @Test
1265     @Ignore("The instrumentation is allowed to star FGS, it does not throw the exception")
testFgsStartFromBGException()1266     public void testFgsStartFromBGException() throws Exception {
1267         ForegroundServiceStartNotAllowedException expectedException = null;
1268         final Intent intent = new Intent().setClassName(
1269                 PACKAGE_NAME_APP1, "android.app.stubs.LocalForegroundService");
1270         try {
1271             allowBgActivityStart("android.app.stubs", false);
1272             enableFgsRestriction(true, true, null);
1273             mContext.startForegroundService(intent);
1274         } catch (ForegroundServiceStartNotAllowedException e) {
1275             expectedException = e;
1276         } finally {
1277             mContext.stopService(intent);
1278             allowBgActivityStart("android.app.stubs", true);
1279         }
1280         String expectedMessage = "mAllowStartForeground false";
1281         assertNotNull(expectedException);
1282         assertTrue(expectedException.getMessage().contains(expectedMessage));
1283     }
1284 
1285     /**
1286      * Test a FGS can start from BG if the app is in the DeviceIdleController's AllowList.
1287      */
1288     @Presubmit
1289     @Test
testFgsStartAllowList()1290     public void testFgsStartAllowList() throws Exception {
1291         ApplicationInfo app1Info = mContext.getPackageManager().getApplicationInfo(
1292                 PACKAGE_NAME_APP1, 0);
1293         WatchUidRunner uid1Watcher = new WatchUidRunner(mInstrumentation, app1Info.uid,
1294                 WAITFOR_MSEC);
1295         try {
1296             // Enable the FGS background startForeground() restriction.
1297             enableFgsRestriction(true, true, null);
1298             // Start FGS in BG state.
1299             WaitForBroadcast waiter = new WaitForBroadcast(mInstrumentation.getTargetContext());
1300             waiter.prepare(ACTION_START_FGS_RESULT);
1301             CommandReceiver.sendCommand(mContext,
1302                     CommandReceiver.COMMAND_START_FOREGROUND_SERVICE,
1303                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
1304             // APP1 does not enter FGS state
1305             try {
1306                 waiter.doWait(WAITFOR_MSEC);
1307                 fail("Service should not enter foreground service state");
1308             } catch (Exception e) {
1309             }
1310 
1311             // Add package to AllowList.
1312             CtsAppTestUtils.executeShellCmd(mInstrumentation,
1313                     "dumpsys deviceidle whitelist +" + PACKAGE_NAME_APP1);
1314             waiter = new WaitForBroadcast(mInstrumentation.getTargetContext());
1315             waiter.prepare(ACTION_START_FGS_RESULT);
1316             // Now it can start FGS.
1317             CommandReceiver.sendCommand(mContext,
1318                     CommandReceiver.COMMAND_START_FOREGROUND_SERVICE,
1319                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
1320             uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_FG_SERVICE);
1321             waiter.doWait(WAITFOR_MSEC);
1322             // Stop the FGS.
1323             CommandReceiver.sendCommand(mContext,
1324                     CommandReceiver.COMMAND_STOP_FOREGROUND_SERVICE,
1325                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
1326             uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_CACHED_EMPTY);
1327         } finally {
1328             uid1Watcher.finish();
1329             // Remove package from AllowList.
1330             CtsAppTestUtils.executeShellCmd(mInstrumentation,
1331                     "dumpsys deviceidle whitelist -" + PACKAGE_NAME_APP1);
1332         }
1333     }
1334 
1335     /**
1336      * Test temp allowlist types in BroadcastOptions.
1337      */
1338     @Presubmit
1339     @Test
testTempAllowListType()1340     public void testTempAllowListType() throws Exception {
1341         testTempAllowListTypeInternal(TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED);
1342         testTempAllowListTypeInternal(TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED);
1343     }
1344 
testTempAllowListTypeInternal(int type)1345     private void testTempAllowListTypeInternal(int type) throws Exception {
1346         ApplicationInfo app1Info = mContext.getPackageManager().getApplicationInfo(
1347                 PACKAGE_NAME_APP1, 0);
1348         ApplicationInfo app2Info = mContext.getPackageManager().getApplicationInfo(
1349                 PACKAGE_NAME_APP2, 0);
1350         WatchUidRunner uid1Watcher = new WatchUidRunner(mInstrumentation, app1Info.uid,
1351                 WAITFOR_MSEC);
1352         WatchUidRunner uid2Watcher = new WatchUidRunner(mInstrumentation, app2Info.uid,
1353                 WAITFOR_MSEC);
1354         try {
1355             // Enable the FGS background startForeground() restriction.
1356             enableFgsRestriction(true, true, null);
1357             // Start FGS in BG state.
1358             WaitForBroadcast waiter = new WaitForBroadcast(mInstrumentation.getTargetContext());
1359             waiter.prepare(ACTION_START_FGS_RESULT);
1360             CommandReceiver.sendCommand(mContext,
1361                     CommandReceiver.COMMAND_START_FOREGROUND_SERVICE,
1362                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP2, 0, null);
1363             // APP1 does not enter FGS state
1364             try {
1365                 waiter.doWait(WAITFOR_MSEC);
1366                 fail("Service should not enter foreground service state");
1367             } catch (Exception e) {
1368             }
1369 
1370             // Now it can start FGS.
1371             waiter = new WaitForBroadcast(mInstrumentation.getTargetContext());
1372             waiter.prepare(ACTION_START_FGS_RESULT);
1373             runWithShellPermissionIdentity(()-> {
1374                 final BroadcastOptions options = BroadcastOptions.makeBasic();
1375                 // setTemporaryAppAllowlist API requires
1376                 // START_FOREGROUND_SERVICES_FROM_BACKGROUND permission.
1377                 options.setTemporaryAppAllowlist(TEMP_ALLOWLIST_DURATION_MS, type, REASON_UNKNOWN,
1378                         "");
1379                 // Must use Shell to issue this command because Shell has
1380                 // START_FOREGROUND_SERVICES_FROM_BACKGROUND permission.
1381                 CommandReceiver.sendCommandWithBroadcastOptions(mContext,
1382                         CommandReceiver.COMMAND_START_FOREGROUND_SERVICE,
1383                         PACKAGE_NAME_APP1, PACKAGE_NAME_APP2, 0, null,
1384                         options.toBundle());
1385             });
1386             if (type == TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED) {
1387                 uid2Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_FG_SERVICE);
1388                 waiter.doWait(WAITFOR_MSEC);
1389                 // Stop the FGS.
1390                 CommandReceiver.sendCommand(mContext,
1391                         CommandReceiver.COMMAND_STOP_FOREGROUND_SERVICE,
1392                         PACKAGE_NAME_APP1, PACKAGE_NAME_APP2, 0, null);
1393                 uid2Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE,
1394                         WatchUidRunner.STATE_CACHED_EMPTY);
1395             } else if (type == TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED) {
1396                 // APP1 does not enter FGS state
1397                 try {
1398                     waiter.doWait(WAITFOR_MSEC);
1399                     fail("Service should not enter foreground service state");
1400                 } catch (Exception e) {
1401                 }
1402             }
1403         } finally {
1404             uid1Watcher.finish();
1405             uid2Watcher.finish();
1406             // Sleep 10 seconds to let the temp allowlist expire so it won't affect next test case.
1407             SystemClock.sleep(TEMP_ALLOWLIST_DURATION_MS);
1408         }
1409 
1410     }
1411 
1412     /**
1413      * Test a FGS can start from BG if the process had a visible activity recently.
1414      */
1415     @LargeTest
1416     @Test
testVisibleActivityGracePeriod()1417     public void testVisibleActivityGracePeriod() throws Exception {
1418         ApplicationInfo app2Info = mContext.getPackageManager().getApplicationInfo(
1419                 PACKAGE_NAME_APP2, 0);
1420         WatchUidRunner uid2Watcher = new WatchUidRunner(mInstrumentation, app2Info.uid,
1421                 WAITFOR_MSEC);
1422         final String namespaceActivityManager = "activity_manager";
1423         final String keyFgToBgFgsGraceDuration = "fg_to_bg_fgs_grace_duration";
1424         final long[] curFgToBgFgsGraceDuration = {-1};
1425         try {
1426             // Enable the FGS background startForeground() restriction.
1427             enableFgsRestriction(true, true, null);
1428             // Allow bg actvity start from APP1.
1429             allowBgActivityStart(PACKAGE_NAME_APP1, true);
1430 
1431             SystemUtil.runWithShellPermissionIdentity(() -> {
1432                 curFgToBgFgsGraceDuration[0] = DeviceConfig.getInt(
1433                         namespaceActivityManager,
1434                         keyFgToBgFgsGraceDuration, -1);
1435                 DeviceConfig.setProperty(namespaceActivityManager,
1436                         keyFgToBgFgsGraceDuration,
1437                         Long.toString(WAITFOR_MSEC), false);
1438             });
1439 
1440             testVisibleActivityGracePeriodInternal(uid2Watcher, "KEYCODE_HOME");
1441             testVisibleActivityGracePeriodInternal(uid2Watcher, "KEYCODE_BACK");
1442         } finally {
1443             uid2Watcher.finish();
1444             // Remove package from AllowList.
1445             allowBgActivityStart(PACKAGE_NAME_APP1, false);
1446             if (curFgToBgFgsGraceDuration[0] >= 0) {
1447                 SystemUtil.runWithShellPermissionIdentity(() -> {
1448                     DeviceConfig.setProperty(namespaceActivityManager,
1449                             keyFgToBgFgsGraceDuration,
1450                             Long.toString(curFgToBgFgsGraceDuration[0]), false);
1451                 });
1452             } else {
1453                 CtsAppTestUtils.executeShellCmd(mInstrumentation,
1454                         "device_config delete " + namespaceActivityManager
1455                         + " " + keyFgToBgFgsGraceDuration);
1456             }
1457         }
1458     }
1459 
testVisibleActivityGracePeriodInternal(WatchUidRunner uidWatcher, String keyCode)1460     private void testVisibleActivityGracePeriodInternal(WatchUidRunner uidWatcher, String keyCode)
1461             throws Exception {
1462         testVisibleActivityGracePeriodInternal(uidWatcher, keyCode, null,
1463                 () -> uidWatcher.waitFor(WatchUidRunner.CMD_PROCSTATE,
1464                         WatchUidRunner.STATE_FG_SERVICE), true);
1465 
1466         testVisibleActivityGracePeriodInternal(uidWatcher, keyCode,
1467                 () -> SystemClock.sleep(WAITFOR_MSEC + 2000), // Wait for the grace period to expire
1468                 () -> {
1469                     try {
1470                         uidWatcher.waitFor(WatchUidRunner.CMD_PROCSTATE,
1471                                 WatchUidRunner.STATE_FG_SERVICE);
1472                         fail("Service should not enter foreground service state");
1473                     } catch (Exception e) {
1474                         // Expected.
1475                     }
1476                 }, false);
1477     }
1478 
testVisibleActivityGracePeriodInternal(WatchUidRunner uidWatcher, String keyCode, Runnable prep, Runnable verifier, boolean stopFgs)1479     private void testVisibleActivityGracePeriodInternal(WatchUidRunner uidWatcher,
1480             String keyCode, Runnable prep, Runnable verifier, boolean stopFgs) throws Exception {
1481         // Put APP2 in TOP state.
1482         CommandReceiver.sendCommand(mContext,
1483                 CommandReceiver.COMMAND_START_ACTIVITY,
1484                 PACKAGE_NAME_APP1, PACKAGE_NAME_APP2, 0, null);
1485         uidWatcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_TOP);
1486 
1487         // Take a nap to wait for the UI to settle down.
1488         SystemClock.sleep(2000);
1489 
1490         // Now inject key event.
1491         CtsAppTestUtils.executeShellCmd(mInstrumentation, "input keyevent " + keyCode);
1492 
1493         // It should go to the cached state.
1494         uidWatcher.waitFor(WatchUidRunner.CMD_CACHED, null);
1495 
1496         if (prep != null) {
1497             prep.run();
1498         }
1499 
1500         // Start FGS from APP2.
1501         CommandReceiver.sendCommand(mContext,
1502                 CommandReceiver.COMMAND_START_FOREGROUND_SERVICE,
1503                 PACKAGE_NAME_APP2, PACKAGE_NAME_APP2, 0, null);
1504 
1505         if (verifier != null) {
1506             verifier.run();
1507         }
1508 
1509         if (stopFgs) {
1510             // Stop the FGS.
1511             CommandReceiver.sendCommand(mContext,
1512                     CommandReceiver.COMMAND_STOP_FOREGROUND_SERVICE,
1513                     PACKAGE_NAME_APP2, PACKAGE_NAME_APP2, 0, null);
1514             uidWatcher.waitFor(WatchUidRunner.CMD_CACHED, null);
1515         }
1516     }
1517 
1518     /**
1519      * After background service is started, after 10 seconds timeout, the startForeground() can
1520      * succeed or not depends on the service's app proc state.
1521      * Test starService() -> startForeground()
1522      */
1523     @Presubmit
1524     @Test
testStartForegroundTimeout()1525     public void testStartForegroundTimeout() throws Exception {
1526         ApplicationInfo app1Info = mContext.getPackageManager().getApplicationInfo(
1527                 PACKAGE_NAME_APP1, 0);
1528         WatchUidRunner uid1Watcher = new WatchUidRunner(mInstrumentation, app1Info.uid,
1529                 WAITFOR_MSEC, PROCESS_CAPABILITY_ALL);
1530         try {
1531             // Enable the FGS background startForeground() restriction.
1532             enableFgsRestriction(true, true, null);
1533             setFgsStartForegroundTimeout(DEFAULT_FGS_START_FOREGROUND_TIMEOUT_MS);
1534 
1535             // Put app to a TOP proc state.
1536             allowBgActivityStart(PACKAGE_NAME_APP1, true);
1537             CommandReceiver.sendCommand(mContext, CommandReceiver.COMMAND_START_ACTIVITY,
1538                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
1539             uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_TOP);
1540             allowBgActivityStart(PACKAGE_NAME_APP1, false);
1541 
1542             // start background service.
1543             Bundle extras = LocalForegroundService.newCommand(
1544                     LocalForegroundService.COMMAND_START_NO_FOREGROUND);
1545             CommandReceiver.sendCommand(mContext, CommandReceiver.COMMAND_START_SERVICE,
1546                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, extras);
1547 
1548             // stop the activity.
1549             CommandReceiver.sendCommand(mContext, CommandReceiver.COMMAND_STOP_ACTIVITY,
1550                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
1551             uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_SERVICE);
1552 
1553             // Sleep after the timeout DEFAULT_FGS_START_FOREGROUND_TIMEOUT_MS
1554             SystemClock.sleep(DEFAULT_FGS_START_FOREGROUND_TIMEOUT_MS + 1000);
1555 
1556             extras = LocalForegroundService.newCommand(
1557                     LocalForegroundService.COMMAND_START_FOREGROUND);
1558             CommandReceiver.sendCommand(mContext, CommandReceiver.COMMAND_START_SERVICE,
1559                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, extras);
1560             // APP1 does not enter FGS state
1561             // startForeground() is called after 10 seconds FgsStartForegroundTimeout.
1562             try {
1563                 uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_FG_SERVICE);
1564                 fail("Service should not enter foreground service state");
1565             } catch (Exception e) {
1566             }
1567 
1568             // Put app to a TOP proc state.
1569             allowBgActivityStart(PACKAGE_NAME_APP1, true);
1570             CommandReceiver.sendCommand(mContext, CommandReceiver.COMMAND_START_ACTIVITY,
1571                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
1572             uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE,
1573                     WatchUidRunner.STATE_TOP, new Integer(PROCESS_CAPABILITY_ALL));
1574             allowBgActivityStart(PACKAGE_NAME_APP1, false);
1575 
1576             // Call startForeground().
1577             WaitForBroadcast waiter = new WaitForBroadcast(mInstrumentation.getTargetContext());
1578             waiter.prepare(ACTION_START_FGS_RESULT);
1579             extras = LocalForegroundService.newCommand(
1580                     LocalForegroundService.COMMAND_START_FOREGROUND);
1581             CommandReceiver.sendCommand(mContext, CommandReceiver.COMMAND_START_SERVICE,
1582                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, extras);
1583             CommandReceiver.sendCommand(mContext, CommandReceiver.COMMAND_STOP_ACTIVITY,
1584                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
1585 
1586             uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_FG_SERVICE);
1587             waiter.doWait(WAITFOR_MSEC);
1588 
1589             // Stop the FGS.
1590             CommandReceiver.sendCommand(mContext, CommandReceiver.COMMAND_STOP_SERVICE,
1591                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
1592             uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_CACHED_EMPTY,
1593                     new Integer(PROCESS_CAPABILITY_NONE));
1594         } finally {
1595             uid1Watcher.finish();
1596             setFgsStartForegroundTimeout(DEFAULT_FGS_START_FOREGROUND_TIMEOUT_MS);
1597         }
1598     }
1599 
1600     /**
1601      * After startForeground() and stopForeground(), the second startForeground() can succeed or not
1602      * depends on the service's app proc state.
1603      * Test startForegroundService() -> startForeground() -> stopForeground() -> startForeground()
1604      * -> startForeground().
1605      */
1606     @Presubmit
1607     @Test
testSecondStartForeground()1608     public void testSecondStartForeground() throws Exception {
1609         ApplicationInfo app1Info = mContext.getPackageManager().getApplicationInfo(
1610                 PACKAGE_NAME_APP1, 0);
1611         WatchUidRunner uid1Watcher = new WatchUidRunner(mInstrumentation, app1Info.uid,
1612                 WAITFOR_MSEC, PROCESS_CAPABILITY_ALL);
1613         try {
1614             // Enable the FGS background startForeground() restriction.
1615             enableFgsRestriction(true, true, null);
1616             WaitForBroadcast waiter = new WaitForBroadcast(mInstrumentation.getTargetContext());
1617             waiter.prepare(ACTION_START_FGS_RESULT);
1618             // Bypass bg-service-start restriction.
1619             CtsAppTestUtils.executeShellCmd(mInstrumentation,
1620                     "dumpsys deviceidle whitelist +" + PACKAGE_NAME_APP1);
1621             // Start foreground service from APP1, the service can enter FGS.
1622             CommandReceiver.sendCommand(mContext, CommandReceiver.COMMAND_START_FOREGROUND_SERVICE,
1623                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
1624             uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_FG_SERVICE);
1625             waiter.doWait(WAITFOR_MSEC);
1626             CtsAppTestUtils.executeShellCmd(mInstrumentation,
1627                     "dumpsys deviceidle whitelist -" + PACKAGE_NAME_APP1);
1628 
1629             // stopForeground(), the service exits FGS, become a background service.
1630             Bundle extras = LocalForegroundService.newCommand(
1631                     LocalForegroundService.COMMAND_STOP_FOREGROUND_REMOVE_NOTIFICATION);
1632             CommandReceiver.sendCommand(mContext, CommandReceiver.COMMAND_START_SERVICE,
1633                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, extras);
1634             uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_SERVICE,
1635                     new Integer(PROCESS_CAPABILITY_NONE));
1636 
1637             // APP2 is in the background, from APP2, call startForeground().
1638             // When APP2 calls Context.startService(), setFgsRestrictionLocked() is called,
1639             // because APP2 is in the background, mAllowStartForeground is set to false.
1640             // When Service.startForeground() is called, setFgsRestrictionLocked() is called again,
1641             // APP1's proc state is in the background and mAllowStartForeground is set to false.
1642             extras = LocalForegroundService.newCommand(
1643                     LocalForegroundService.COMMAND_START_FOREGROUND);
1644             CommandReceiver.sendCommand(mContext, CommandReceiver.COMMAND_START_SERVICE,
1645                     PACKAGE_NAME_APP2, PACKAGE_NAME_APP1, 0, extras);
1646             try {
1647                 uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_FG_SERVICE);
1648                 fail("Service should not enter foreground service state");
1649             } catch (Exception e) {
1650             }
1651 
1652             // Put APP1 to a TOP proc state.
1653             allowBgActivityStart(PACKAGE_NAME_APP1, true);
1654             CommandReceiver.sendCommand(mContext, CommandReceiver.COMMAND_START_ACTIVITY,
1655                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
1656             uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_TOP,
1657                     new Integer(PROCESS_CAPABILITY_ALL));
1658             allowBgActivityStart(PACKAGE_NAME_APP1, false);
1659 
1660             // APP2 is in the background, from APP2, call startForeground() second time.
1661             // When APP2 calls Context.startService(), setFgsRestrictionLocked() is called,
1662             // because APP2 is in the background, mAllowStartForeground is set to false.
1663             // When Service.startForeground() is called, setFgsRestrictionLocked() is called again,
1664             // because APP1's proc state is in the foreground and mAllowStartForeground is set to
1665             // true.
1666             waiter = new WaitForBroadcast(mInstrumentation.getTargetContext());
1667             waiter.prepare(ACTION_START_FGS_RESULT);
1668             extras = LocalForegroundService.newCommand(
1669                     LocalForegroundService.COMMAND_START_FOREGROUND);
1670             extras.putInt(LocalForegroundServiceLocation.EXTRA_FOREGROUND_SERVICE_TYPE,
1671                     ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA
1672                     | ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE);
1673             CommandReceiver.sendCommand(mContext, CommandReceiver.COMMAND_START_SERVICE,
1674                     PACKAGE_NAME_APP2, PACKAGE_NAME_APP1, 0, extras);
1675             waiter.doWait(WAITFOR_MSEC);
1676             // Stop app1's activity.
1677             CommandReceiver.sendCommand(mContext, CommandReceiver.COMMAND_STOP_ACTIVITY,
1678                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
1679             uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_FG_SERVICE,
1680                     LOCAL_SERVICE_PROCESS_CAPABILITY);
1681 
1682             // Stop the FGS.
1683             CommandReceiver.sendCommand(mContext, CommandReceiver.COMMAND_STOP_FOREGROUND_SERVICE,
1684                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
1685             uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_CACHED_EMPTY,
1686                     new Integer(PROCESS_CAPABILITY_NONE));
1687         } finally {
1688             uid1Watcher.finish();
1689         }
1690     }
1691 
1692     /**
1693      * Test OP_ACTIVATE_VPN and OP_ACTIVATE_PLATFORM_VPN are exempted from BG-FGS-launch
1694      * restriction.
1695      * @throws Exception
1696      */
1697     @Presubmit
1698     @Test
testFgsStartVpn()1699     public void testFgsStartVpn() throws Exception {
1700         testFgsStartVpnInternal("ACTIVATE_VPN");
1701         testFgsStartVpnInternal("ACTIVATE_PLATFORM_VPN");
1702     }
1703 
testFgsStartVpnInternal(String vpnAppOp)1704     private void testFgsStartVpnInternal(String vpnAppOp) throws Exception {
1705         ApplicationInfo app1Info = mContext.getPackageManager().getApplicationInfo(
1706                 PACKAGE_NAME_APP1, 0);
1707         WatchUidRunner uid1Watcher = new WatchUidRunner(mInstrumentation, app1Info.uid,
1708                 WAITFOR_MSEC);
1709         try {
1710             // Enable the FGS background startForeground() restriction.
1711             enableFgsRestriction(true, true, null);
1712             // Start FGS in BG state.
1713             WaitForBroadcast waiter = new WaitForBroadcast(mInstrumentation.getTargetContext());
1714             waiter.prepare(ACTION_START_FGS_RESULT);
1715             CommandReceiver.sendCommand(mContext,
1716                     CommandReceiver.COMMAND_START_FOREGROUND_SERVICE,
1717                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
1718             // APP1 does not enter FGS state
1719             try {
1720                 waiter.doWait(WAITFOR_MSEC);
1721                 fail("Service should not enter foreground service state");
1722             } catch (Exception e) {
1723             }
1724 
1725             setAppOp(PACKAGE_NAME_APP1, vpnAppOp, true);
1726 
1727             waiter = new WaitForBroadcast(mInstrumentation.getTargetContext());
1728             waiter.prepare(ACTION_START_FGS_RESULT);
1729             // Now it can start FGS.
1730             CommandReceiver.sendCommand(mContext,
1731                     CommandReceiver.COMMAND_START_FOREGROUND_SERVICE,
1732                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
1733             uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_FG_SERVICE);
1734             waiter.doWait(WAITFOR_MSEC);
1735             // Stop the FGS.
1736             CommandReceiver.sendCommand(mContext,
1737                     CommandReceiver.COMMAND_STOP_FOREGROUND_SERVICE,
1738                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
1739             uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_CACHED_EMPTY);
1740         } finally {
1741             uid1Watcher.finish();
1742             CtsAppTestUtils.executeShellCmd(mInstrumentation,
1743                     "appops reset " + PACKAGE_NAME_APP1);
1744         }
1745     }
1746 
1747     /**
1748      * The default behavior for temp allowlist reasonCode REASON_PUSH_MESSAGING_OVER_QUOTA
1749      * is TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED (not allowed to start FGS). But
1750      * the behavior can be changed by device config command. There are three possible values:
1751      * {@link TEMPORARY_ALLOW_LIST_TYPE_NONE} (-1):
1752      * not temp allowlisted.
1753      * {@link TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED} (0):
1754      * temp allowlisted and allow FGS.
1755      * {@link TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED} (1):
1756      * temp allowlisted, not allow FGS.
1757      */
1758     @Presubmit
1759     @Test
testPushMessagingOverQuota()1760     public void testPushMessagingOverQuota() throws Exception {
1761         ApplicationInfo app1Info = mContext.getPackageManager().getApplicationInfo(
1762                 PACKAGE_NAME_APP1, 0);
1763         WatchUidRunner uid1Watcher = new WatchUidRunner(mInstrumentation, app1Info.uid,
1764                 WAITFOR_MSEC);
1765         final int defaultBehavior = getPushMessagingOverQuotaBehavior();
1766         try {
1767             // Enable the FGS background startForeground() restriction.
1768             enableFgsRestriction(true, true, null);
1769             // Default behavior is TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED.
1770             setPushMessagingOverQuotaBehavior(
1771                     TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED);
1772             // Start FGS in BG state.
1773             WaitForBroadcast waiter = new WaitForBroadcast(mInstrumentation.getTargetContext());
1774             waiter.prepare(ACTION_START_FGS_RESULT);
1775             CommandReceiver.sendCommand(mContext,
1776                     CommandReceiver.COMMAND_START_FOREGROUND_SERVICE,
1777                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
1778             // APP1 does not enter FGS state
1779             try {
1780                 waiter.doWait(WAITFOR_MSEC);
1781                 fail("Service should not enter foreground service state");
1782             } catch (Exception e) {
1783             }
1784 
1785             setPushMessagingOverQuotaBehavior(TEMPORARY_ALLOW_LIST_TYPE_NONE);
1786             waiter = new WaitForBroadcast(mInstrumentation.getTargetContext());
1787             waiter.prepare(ACTION_START_FGS_RESULT);
1788             runWithShellPermissionIdentity(() -> {
1789                 mContext.getSystemService(PowerExemptionManager.class).addToTemporaryAllowList(
1790                         PACKAGE_NAME_APP1, PowerExemptionManager.REASON_PUSH_MESSAGING_OVER_QUOTA,
1791                         "", TEMP_ALLOWLIST_DURATION_MS);
1792             });
1793             CommandReceiver.sendCommand(mContext,
1794                     CommandReceiver.COMMAND_START_FOREGROUND_SERVICE,
1795                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
1796             // APP1 does not enter FGS state
1797             try {
1798                 waiter.doWait(WAITFOR_MSEC);
1799                 fail("Service should not enter foreground service state");
1800             } catch (Exception e) {
1801             }
1802 
1803             // Change behavior to TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED.
1804             setPushMessagingOverQuotaBehavior(
1805                     TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED);
1806             runWithShellPermissionIdentity(() -> {
1807                 mContext.getSystemService(PowerExemptionManager.class).addToTemporaryAllowList(
1808                         PACKAGE_NAME_APP1, PowerExemptionManager.REASON_PUSH_MESSAGING_OVER_QUOTA,
1809                         "", TEMP_ALLOWLIST_DURATION_MS);
1810             });
1811             waiter = new WaitForBroadcast(mInstrumentation.getTargetContext());
1812             waiter.prepare(ACTION_START_FGS_RESULT);
1813             // Now it can start FGS.
1814             CommandReceiver.sendCommand(mContext,
1815                     CommandReceiver.COMMAND_START_FOREGROUND_SERVICE,
1816                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
1817             uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_FG_SERVICE);
1818             waiter.doWait(WAITFOR_MSEC);
1819             // Stop the FGS.
1820             CommandReceiver.sendCommand(mContext,
1821                     CommandReceiver.COMMAND_STOP_FOREGROUND_SERVICE,
1822                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
1823             uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_CACHED_EMPTY);
1824         } finally {
1825             uid1Watcher.finish();
1826             // Change back to default behavior.
1827             setPushMessagingOverQuotaBehavior(defaultBehavior);
1828             // allow temp allowlist to expire.
1829             SystemClock.sleep(TEMP_ALLOWLIST_DURATION_MS);
1830         }
1831     }
1832 
1833     /**
1834      * Test temp allowlist reasonCode in BroadcastOptions.
1835      * When REASON_PUSH_MESSAGING_OVER_QUOTA, DeviceIdleController changes temp allowlist type to
1836      * TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED so FGS start is not allowed.
1837      * When REASON_DENIED (-1), DeviceIdleController changes temp allowlist type to
1838      * TEMPORARY_ALLOWLIST_TYPE_NONE, the temp allowlist itself is not allowed.
1839      * All other reason codes, DeviceIdleController does not change temp allowlist type.
1840      */
1841     @Presubmit
1842     @Test
testTempAllowListReasonCode()1843     public void testTempAllowListReasonCode() throws Exception {
1844         // FGS start is temp allowed.
1845         testTempAllowListReasonCodeInternal(REASON_PUSH_MESSAGING);
1846         // FGS start is not allowed.
1847         testTempAllowListReasonCodeInternal(REASON_PUSH_MESSAGING_OVER_QUOTA);
1848         // Temp allowlist itself is not allowed. REASON_DENIED is not exposed in
1849         // PowerExemptionManager, just use its value "-1" here.
1850         testTempAllowListReasonCodeInternal(-1);
1851     }
1852 
testTempAllowListReasonCodeInternal(int reasonCode)1853     private void testTempAllowListReasonCodeInternal(int reasonCode) throws Exception {
1854         ApplicationInfo app1Info = mContext.getPackageManager().getApplicationInfo(
1855                 PACKAGE_NAME_APP1, 0);
1856         ApplicationInfo app2Info = mContext.getPackageManager().getApplicationInfo(
1857                 PACKAGE_NAME_APP2, 0);
1858         WatchUidRunner uid1Watcher = new WatchUidRunner(mInstrumentation, app1Info.uid,
1859                 WAITFOR_MSEC);
1860         WatchUidRunner uid2Watcher = new WatchUidRunner(mInstrumentation, app2Info.uid,
1861                 WAITFOR_MSEC);
1862         final int defaultBehavior = getPushMessagingOverQuotaBehavior();
1863         try {
1864             setPushMessagingOverQuotaBehavior(
1865                     TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED);
1866             // Enable the FGS background startForeground() restriction.
1867             enableFgsRestriction(true, true, null);
1868             // Now it can start FGS.
1869             WaitForBroadcast waiter = new WaitForBroadcast(mInstrumentation.getTargetContext());
1870             waiter.prepare(ACTION_START_FGS_RESULT);
1871             runWithShellPermissionIdentity(() -> {
1872                 final BroadcastOptions options = BroadcastOptions.makeBasic();
1873                 // setTemporaryAppAllowlist API requires
1874                 // START_FOREGROUND_SERVICES_FROM_BACKGROUND permission.
1875                 options.setTemporaryAppAllowlist(TEMP_ALLOWLIST_DURATION_MS,
1876                         TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED, reasonCode,
1877                         "");
1878                 // Must use Shell to issue this command because Shell has
1879                 // START_FOREGROUND_SERVICES_FROM_BACKGROUND permission.
1880                 CommandReceiver.sendCommandWithBroadcastOptions(mContext,
1881                         CommandReceiver.COMMAND_START_FOREGROUND_SERVICE,
1882                         PACKAGE_NAME_APP1, PACKAGE_NAME_APP2, 0, null,
1883                         options.toBundle());
1884             });
1885             if (reasonCode == REASON_PUSH_MESSAGING) {
1886                 uid2Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_FG_SERVICE);
1887                 waiter.doWait(WAITFOR_MSEC);
1888                 // Stop the FGS.
1889                 CommandReceiver.sendCommand(mContext,
1890                         CommandReceiver.COMMAND_STOP_FOREGROUND_SERVICE,
1891                         PACKAGE_NAME_APP1, PACKAGE_NAME_APP2, 0, null);
1892                 uid2Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE,
1893                         WatchUidRunner.STATE_CACHED_EMPTY);
1894             } else if (reasonCode == REASON_PUSH_MESSAGING_OVER_QUOTA) {
1895                 // APP1 does not enter FGS state
1896                 try {
1897                     waiter.doWait(WAITFOR_MSEC);
1898                     fail("Service should not enter foreground service state");
1899                 } catch (Exception e) {
1900                 }
1901             }
1902         } finally {
1903             uid1Watcher.finish();
1904             uid2Watcher.finish();
1905             setPushMessagingOverQuotaBehavior(defaultBehavior);
1906             // Sleep to let the temp allowlist expire so it won't affect next test case.
1907             SystemClock.sleep(TEMP_ALLOWLIST_DURATION_MS);
1908         }
1909     }
1910 
1911     /**
1912      * AlarmManagerService uses REASON_ALARM_MANAGER_ALARM_CLOCK(301) to temp allow FGS start.
1913      * Test when temp allowlist reasonCode is REASON_ALARM_MANAGER_ALARM_CLOCK, even the app is
1914      * background-restricted (appop RUN_ANY_IN_BACKGROUND is false), the app can still start FGS.
1915      */
1916     @Presubmit
1917     @Test
testTempAllowListReasonCodeAlarmClock()1918     public void testTempAllowListReasonCodeAlarmClock() throws Exception {
1919         ApplicationInfo app1Info = mContext.getPackageManager().getApplicationInfo(
1920                 PACKAGE_NAME_APP1, 0);
1921         WatchUidRunner uid1Watcher = new WatchUidRunner(mInstrumentation, app1Info.uid,
1922                 WAITFOR_MSEC);
1923         final String dumpCommand = "dumpsys activity services " + PACKAGE_NAME_APP1
1924                 + "/android.app.stubs.LocalForegroundService";
1925         try {
1926             // Set APP1 to be background-restricted.
1927             setAppOp(PACKAGE_NAME_APP1, "RUN_ANY_IN_BACKGROUND", false);
1928             // Enable the FGS background startForeground() restriction.
1929             enableFgsRestriction(true, true, null);
1930             WaitForBroadcast waiter = new WaitForBroadcast(mInstrumentation.getTargetContext());
1931             waiter.prepare(ACTION_START_FGS_RESULT);
1932             runWithShellPermissionIdentity(() -> {
1933                 final BroadcastOptions options = BroadcastOptions.makeBasic();
1934                 // setTemporaryAppAllowlist API requires
1935                 // START_FOREGROUND_SERVICES_FROM_BACKGROUND permission.
1936                 options.setTemporaryAppAllowlist(TEMP_ALLOWLIST_DURATION_MS,
1937                         TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
1938                         REASON_ALARM_MANAGER_ALARM_CLOCK,
1939                         "");
1940                 // Must use Shell to issue this command because Shell has
1941                 // START_FOREGROUND_SERVICES_FROM_BACKGROUND permission.
1942                 CommandReceiver.sendCommandWithBroadcastOptions(mContext,
1943                         CommandReceiver.COMMAND_START_FOREGROUND_SERVICE,
1944                         PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null,
1945                         options.toBundle());
1946             });
1947             // Although APP1 is background-restricted, FGS can still start because temp allowlist
1948             // reasonCode is REASON_ALARM_MANAGER_ALARM_CLOCK.
1949             uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_FG_SERVICE);
1950             waiter.doWait(WAITFOR_MSEC);
1951             String[] dumpLines = CtsAppTestUtils.executeShellCmd(
1952                     mInstrumentation, dumpCommand).split("\n");
1953             assertNotNull(CtsAppTestUtils.findLine(dumpLines, "isForeground=true"));
1954             // Stop the FGS.
1955             CommandReceiver.sendCommand(mContext,
1956                     CommandReceiver.COMMAND_STOP_FOREGROUND_SERVICE,
1957                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
1958             uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE,
1959                     WatchUidRunner.STATE_CACHED_EMPTY);
1960         } finally {
1961             uid1Watcher.finish();
1962             CtsAppTestUtils.executeShellCmd(mInstrumentation,
1963                     "appops reset " + PACKAGE_NAME_APP1);
1964             // Sleep to let the temp allowlist expire so it won't affect next test case.
1965             SystemClock.sleep(TEMP_ALLOWLIST_DURATION_MS);
1966         }
1967     }
1968 
1969     /**
1970      * FGS is already started because the app is temp allowlisted. Afterwards, when the
1971      * app becomes background-restricted, if the FGS start reasonCode is
1972      * REASON_ALARM_MANAGER_ALARM_CLOCK, FGS can keep running.
1973      */
1974     @Presubmit
1975     @Test
testAlarmClockFgsNotStoppedByBackgroundRestricted()1976     public void testAlarmClockFgsNotStoppedByBackgroundRestricted() throws Exception {
1977         testAlarmClockFgsNotStoppedByBackgroundRestrictedInternal(REASON_ALARM_MANAGER_ALARM_CLOCK);
1978     }
1979 
1980     /**
1981      * FGS is already started because the app is temp allowlisted. Afterwards, when the
1982      * app becomes background-restricted, if the FGS start reasonCode is NOT
1983      * REASON_ALARM_MANAGER_ALARM_CLOCK, the FGS is stopped.
1984      */
1985     @Presubmit
1986     @Test
testFgsStoppedByBackgroundRestricted()1987     public void testFgsStoppedByBackgroundRestricted() throws Exception {
1988         testAlarmClockFgsNotStoppedByBackgroundRestrictedInternal(REASON_UNKNOWN);
1989     }
1990 
testAlarmClockFgsNotStoppedByBackgroundRestrictedInternal(int reasonCode)1991     private void testAlarmClockFgsNotStoppedByBackgroundRestrictedInternal(int reasonCode)
1992             throws Exception {
1993         ApplicationInfo app1Info = mContext.getPackageManager().getApplicationInfo(
1994                 PACKAGE_NAME_APP1, 0);
1995         WatchUidRunner uid1Watcher = new WatchUidRunner(mInstrumentation, app1Info.uid,
1996                 WAITFOR_MSEC);
1997         final String dumpCommand = "dumpsys activity services " + PACKAGE_NAME_APP1
1998                 + "/android.app.stubs.LocalForegroundService";
1999         final long shortWaitMsec = 5_000;
2000         try {
2001             // Enable the FGS background startForeground() restriction.
2002             enableFgsRestriction(true, true, null);
2003             WaitForBroadcast waiter = new WaitForBroadcast(mInstrumentation.getTargetContext());
2004             waiter.prepare(ACTION_START_FGS_RESULT);
2005             runWithShellPermissionIdentity(() -> {
2006                 final BroadcastOptions options = BroadcastOptions.makeBasic();
2007                 // setTemporaryAppAllowlist API requires
2008                 // START_FOREGROUND_SERVICES_FROM_BACKGROUND permission.
2009                 options.setTemporaryAppAllowlist(TEMP_ALLOWLIST_DURATION_MS,
2010                         TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
2011                         reasonCode,
2012                         "");
2013                 // Must use Shell to issue this command because Shell has
2014                 // START_FOREGROUND_SERVICES_FROM_BACKGROUND permission.
2015                 CommandReceiver.sendCommandWithBroadcastOptions(mContext,
2016                         CommandReceiver.COMMAND_START_FOREGROUND_SERVICE,
2017                         PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null,
2018                         options.toBundle());
2019             });
2020             uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_FG_SERVICE);
2021             waiter.doWait(WAITFOR_MSEC);
2022             String[] dumpLines = CtsAppTestUtils.executeShellCmd(
2023                     mInstrumentation, dumpCommand).split("\n");
2024             assertNotNull(CtsAppTestUtils.findLine(dumpLines, "isForeground=true"));
2025 
2026             // Set APP1 to be background-restricted.
2027             setAppOp(PACKAGE_NAME_APP1, "RUN_ANY_IN_BACKGROUND", false);
2028             if (reasonCode == REASON_ALARM_MANAGER_ALARM_CLOCK) {
2029                 SystemClock.sleep(shortWaitMsec);
2030                 // Because the FGS start reasonCode is REASON_ALARM_MANAGER_ALARM_CLOCK, when the
2031                 // app becomes background-restricted, its FGS can keep running.
2032                 dumpLines = CtsAppTestUtils.executeShellCmd(
2033                         mInstrumentation, dumpCommand).split("\n");
2034                 assertNotNull(CtsAppTestUtils.findLine(dumpLines, "isForeground=true"));
2035                 // Stop the FGS.
2036                 CommandReceiver.sendCommand(mContext,
2037                         CommandReceiver.COMMAND_STOP_FOREGROUND_SERVICE,
2038                         PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
2039                 uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE,
2040                         WatchUidRunner.STATE_CACHED_EMPTY);
2041             } else {
2042                 SystemClock.sleep(shortWaitMsec);
2043                 // For other reasonCode, when the app is background-restricted, FGS is stopped.
2044                 dumpLines = CtsAppTestUtils.executeShellCmd(
2045                         mInstrumentation, dumpCommand).split("\n");
2046                 assertNull(CtsAppTestUtils.findLine(dumpLines, "isForeground=true"));
2047             }
2048         } finally {
2049             uid1Watcher.finish();
2050             CtsAppTestUtils.executeShellCmd(mInstrumentation,
2051                     "appops reset " + PACKAGE_NAME_APP1);
2052             // Sleep to let the temp allowlist expire so it won't affect next test case.
2053             SystemClock.sleep(TEMP_ALLOWLIST_DURATION_MS);
2054         }
2055     }
2056 
2057     /**
2058      * Test default_input_method is exempted from BG-FGS-start restriction.
2059      * @throws Exception
2060      */
2061     @Presubmit
2062     @Test
testFgsStartInputMethod()2063     public void testFgsStartInputMethod() throws Exception {
2064         ApplicationInfo app1Info = mContext.getPackageManager().getApplicationInfo(
2065                 PACKAGE_NAME_APP1, 0);
2066         WatchUidRunner uid1Watcher = new WatchUidRunner(mInstrumentation, app1Info.uid,
2067                 WAITFOR_MSEC);
2068         final String defaultInputMethod = CtsAppTestUtils.executeShellCmd(mInstrumentation,
2069                 "settings get --user current secure default_input_method");
2070         try {
2071             // Enable the FGS background startForeground() restriction.
2072             enableFgsRestriction(true, true, null);
2073             // Start FGS in BG state.
2074             WaitForBroadcast waiter = new WaitForBroadcast(mInstrumentation.getTargetContext());
2075             waiter.prepare(ACTION_START_FGS_RESULT);
2076             CommandReceiver.sendCommand(mContext,
2077                     CommandReceiver.COMMAND_START_FOREGROUND_SERVICE,
2078                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
2079             // APP1 does not enter FGS state
2080             try {
2081                 waiter.doWait(WAITFOR_MSEC);
2082                 fail("Service should not enter foreground service state");
2083             } catch (Exception e) {
2084             }
2085 
2086             // Change default_input_method to PACKAGE_NAME_APP1.
2087             final ComponentName cn = new ComponentName(PACKAGE_NAME_APP1, "xxx");
2088             CtsAppTestUtils.executeShellCmd(mInstrumentation,
2089                     "settings put --user current secure default_input_method "
2090                             + cn.flattenToShortString());
2091 
2092             waiter = new WaitForBroadcast(mInstrumentation.getTargetContext());
2093             waiter.prepare(ACTION_START_FGS_RESULT);
2094             // Now it can start FGS.
2095             CommandReceiver.sendCommand(mContext,
2096                     CommandReceiver.COMMAND_START_FOREGROUND_SERVICE,
2097                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
2098             uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_FG_SERVICE);
2099             waiter.doWait(WAITFOR_MSEC);
2100             // Stop the FGS.
2101             CommandReceiver.sendCommand(mContext,
2102                     CommandReceiver.COMMAND_STOP_FOREGROUND_SERVICE,
2103                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
2104             uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_CACHED_EMPTY);
2105         } finally {
2106             uid1Watcher.finish();
2107             CtsAppTestUtils.executeShellCmd(mInstrumentation,
2108                     "settings put --user current secure default_input_method "
2109                             + defaultInputMethod);
2110         }
2111     }
2112 
2113     @Presubmit
2114     @Test
testFgsStartInBackgroundRestrictions()2115     public void testFgsStartInBackgroundRestrictions() throws Exception {
2116         ApplicationInfo app1Info = mContext.getPackageManager().getApplicationInfo(
2117                 PACKAGE_NAME_APP1, 0);
2118         ApplicationInfo app2Info = mContext.getPackageManager().getApplicationInfo(
2119                 PACKAGE_NAME_APP2, 0);
2120         WatchUidRunner uid1Watcher = new WatchUidRunner(mInstrumentation, app1Info.uid,
2121                 WAITFOR_MSEC);
2122         WatchUidRunner uid2Watcher = new WatchUidRunner(mInstrumentation, app2Info.uid,
2123                 WAITFOR_MSEC);
2124         WaitForBroadcast waiter = new WaitForBroadcast(mInstrumentation.getTargetContext());
2125         final String dumpCommand = "dumpsys activity services " + PACKAGE_NAME_APP2
2126                 + "/android.app.stubs.LocalForegroundService";
2127         final long shortWaitMsec = 5_000;
2128         try {
2129             // Enable the FGS background startForeground() restriction.
2130             enableFgsRestriction(true, true, null);
2131 
2132             // Set background restriction for APP2
2133             setAppOp(PACKAGE_NAME_APP2, "RUN_ANY_IN_BACKGROUND", false);
2134 
2135             // Start the APP1 into the TOP state.
2136             allowBgActivityStart(PACKAGE_NAME_APP1, true);
2137             CommandReceiver.sendCommand(mContext,
2138                     CommandReceiver.COMMAND_START_ACTIVITY,
2139                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
2140             uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE,
2141                     WatchUidRunner.STATE_TOP);
2142 
2143             // APP1 binds to APP2.
2144             CommandReceiver.sendCommand(mContext, CommandReceiver.COMMAND_BIND_SERVICE,
2145                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP2, Context.BIND_INCLUDE_CAPABILITIES, null);
2146 
2147             // APP2 gets proc state BOUND_TOP.
2148             uid2Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE,
2149                     WatchUidRunner.STATE_BOUND_TOP);
2150 
2151             waiter = new WaitForBroadcast(mInstrumentation.getTargetContext());
2152             waiter.prepare(ACTION_START_FGS_RESULT);
2153 
2154             // START FGS in APP2.
2155             CommandReceiver.sendCommand(mContext,
2156                     CommandReceiver.COMMAND_START_FOREGROUND_SERVICE,
2157                     PACKAGE_NAME_APP2, PACKAGE_NAME_APP2, 0, null);
2158             waiter.doWait(WAITFOR_MSEC);
2159 
2160             SystemClock.sleep(shortWaitMsec);
2161 
2162             String[] dumpLines = CtsAppTestUtils.executeShellCmd(
2163                     mInstrumentation, dumpCommand).split("\n");
2164             assertNotNull(CtsAppTestUtils.findLine(dumpLines, "isForeground=true"));
2165 
2166             // Finish the activity in APP1
2167             CommandReceiver.sendCommand(mContext,
2168                     CommandReceiver.COMMAND_STOP_ACTIVITY,
2169                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
2170             mInstrumentation.getUiAutomation().performGlobalAction(
2171                     AccessibilityService.GLOBAL_ACTION_HOME);
2172 
2173             // APP1 should have been cached state now.
2174             uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE,
2175                     WatchUidRunner.STATE_CACHED_EMPTY);
2176 
2177             // Th FGS in APP2 should have been normal service state now.
2178             uid2Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE,
2179                     WatchUidRunner.STATE_SERVICE);
2180 
2181             waiter = new WaitForBroadcast(mInstrumentation.getTargetContext());
2182             waiter.prepare(ACTION_START_FGS_RESULT);
2183 
2184             // START FGS in APP1
2185             CommandReceiver.sendCommand(mContext,
2186                     CommandReceiver.COMMAND_START_FOREGROUND_SERVICE,
2187                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
2188             uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE,
2189                     WatchUidRunner.STATE_FG_SERVICE);
2190             waiter.doWait(WAITFOR_MSEC);
2191 
2192             // APP2 should be in FGS state too now.
2193             uid2Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE,
2194                     WatchUidRunner.STATE_FG_SERVICE);
2195 
2196             waiter = new WaitForBroadcast(mInstrumentation.getTargetContext());
2197             waiter.prepare(ACTION_START_FGS_RESULT);
2198 
2199             // START FGS in APP2.
2200             CommandReceiver.sendCommand(mContext,
2201                     CommandReceiver.COMMAND_START_FOREGROUND_SERVICE,
2202                     PACKAGE_NAME_APP2, PACKAGE_NAME_APP2, 0, null);
2203             waiter.doWait(WAITFOR_MSEC);
2204 
2205             SystemClock.sleep(shortWaitMsec);
2206 
2207             dumpLines = CtsAppTestUtils.executeShellCmd(
2208                     mInstrumentation, dumpCommand).split("\n");
2209             assertNotNull(CtsAppTestUtils.findLine(dumpLines, "isForeground=true"));
2210 
2211             // Set background restriction for APP1.
2212             setAppOp(PACKAGE_NAME_APP1, "RUN_ANY_IN_BACKGROUND", false);
2213 
2214             // Both of them should have normal service state now.
2215             uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE,
2216                     WatchUidRunner.STATE_SERVICE);
2217             uid2Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE,
2218                     WatchUidRunner.STATE_SERVICE);
2219         } finally {
2220             uid1Watcher.finish();
2221             uid2Watcher.finish();
2222             CtsAppTestUtils.executeShellCmd(mInstrumentation,
2223                     "appops reset " + PACKAGE_NAME_APP1);
2224             CtsAppTestUtils.executeShellCmd(mInstrumentation,
2225                     "appops reset " + PACKAGE_NAME_APP2);
2226         }
2227     }
2228 
2229     /**
2230      * When PowerExemptionManager.addToTemporaryAllowList() is called more than one time, the second
2231      * call can extend the duration of the first call if the first call has not expired yet.
2232      * @throws Exception
2233      */
2234     @Presubmit
2235     @Test
testOverlappedTempAllowList()2236     public void testOverlappedTempAllowList() throws Exception {
2237         ApplicationInfo app1Info = mContext.getPackageManager().getApplicationInfo(
2238                 PACKAGE_NAME_APP1, 0);
2239         WatchUidRunner uid1Watcher = new WatchUidRunner(mInstrumentation, app1Info.uid,
2240                 WAITFOR_MSEC);
2241         try {
2242             // Enable the FGS background startForeground() restriction.
2243             enableFgsRestriction(true, true, null);
2244             // Start FGS in BG state.
2245             WaitForBroadcast waiter = new WaitForBroadcast(mInstrumentation.getTargetContext());
2246             waiter.prepare(ACTION_START_FGS_RESULT);
2247             CommandReceiver.sendCommand(mContext,
2248                     CommandReceiver.COMMAND_START_FOREGROUND_SERVICE,
2249                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
2250             // APP1 does not enter FGS state
2251             try {
2252                 waiter.doWait(WAITFOR_MSEC);
2253                 fail("Service should not enter foreground service state");
2254             } catch (Exception e) {
2255             }
2256 
2257             waiter = new WaitForBroadcast(mInstrumentation.getTargetContext());
2258             waiter.prepare(ACTION_START_FGS_RESULT);
2259             runWithShellPermissionIdentity(() -> {
2260                 mContext.getSystemService(PowerExemptionManager.class).addToTemporaryAllowList(
2261                         PACKAGE_NAME_APP1, PowerExemptionManager.REASON_PUSH_MESSAGING,
2262                         "", 10000);
2263             });
2264 
2265             SystemClock.sleep(5000);
2266             runWithShellPermissionIdentity(() -> {
2267                 mContext.getSystemService(PowerExemptionManager.class).addToTemporaryAllowList(
2268                         PACKAGE_NAME_APP1, PowerExemptionManager.REASON_PUSH_MESSAGING,
2269                         "", 10000);
2270             });
2271             SystemClock.sleep(5000);
2272 
2273             // The first addToTemporaryAllowList()'s 10000ms duration has expired.
2274             // Now FGS start is allowed by second addToTemporaryAllowList()'s 10000ms duration.
2275             waiter = new WaitForBroadcast(mInstrumentation.getTargetContext());
2276             waiter.prepare(ACTION_START_FGS_RESULT);
2277             // Now it can start FGS.
2278             CommandReceiver.sendCommand(mContext,
2279                     CommandReceiver.COMMAND_START_FOREGROUND_SERVICE,
2280                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
2281             uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_FG_SERVICE);
2282             waiter.doWait(WAITFOR_MSEC);
2283             // Stop the FGS.
2284             CommandReceiver.sendCommand(mContext,
2285                     CommandReceiver.COMMAND_STOP_FOREGROUND_SERVICE,
2286                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
2287             uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_CACHED_EMPTY);
2288         } finally {
2289             uid1Watcher.finish();
2290             // allow temp allowlist to expire.
2291             SystemClock.sleep(5000);
2292         }
2293     }
2294 
2295     /**
2296      * Test overlapped BroadcastOptions.setTemporaryAppAllowlist().
2297      * This is similar to test case testOverlappedTempAllowList which is
2298      * PowerExemptionManager.addToTemporaryAllowList().
2299      */
2300     @Presubmit
2301     @Test
testOverlappedTempAllowListByBroadcastOptions()2302     public void testOverlappedTempAllowListByBroadcastOptions() throws Exception {
2303         ApplicationInfo app1Info = mContext.getPackageManager().getApplicationInfo(
2304                 PACKAGE_NAME_APP1, 0);
2305         ApplicationInfo app2Info = mContext.getPackageManager().getApplicationInfo(
2306                 PACKAGE_NAME_APP2, 0);
2307         WatchUidRunner uid1Watcher = new WatchUidRunner(mInstrumentation, app1Info.uid,
2308                 WAITFOR_MSEC);
2309         WatchUidRunner uid2Watcher = new WatchUidRunner(mInstrumentation, app2Info.uid,
2310                 WAITFOR_MSEC);
2311         try {
2312             // Enable the FGS background startForeground() restriction.
2313             enableFgsRestriction(true, true, null);
2314             WaitForBroadcast waiter = new WaitForBroadcast(mInstrumentation.getTargetContext());
2315             waiter.prepare(ACTION_START_FGS_RESULT);
2316             runWithShellPermissionIdentity(()-> {
2317                 final BroadcastOptions options = BroadcastOptions.makeBasic();
2318                 // setTemporaryAppAllowlist API requires
2319                 // START_FOREGROUND_SERVICES_FROM_BACKGROUND permission.
2320                 options.setTemporaryAppAllowlist(10000,
2321                         TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED, REASON_UNKNOWN,
2322                         "10seconds_br_options");
2323                 // Must use Shell to issue this command because Shell has
2324                 // START_FOREGROUND_SERVICES_FROM_BACKGROUND permission.
2325                 CommandReceiver.sendCommandWithBroadcastOptions(mContext,
2326                         CommandReceiver.COMMAND_START_FOREGROUND_SERVICE,
2327                         PACKAGE_NAME_APP1, PACKAGE_NAME_APP2, 0, null,
2328                         options.toBundle());
2329             });
2330 
2331             uid2Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_FG_SERVICE);
2332             waiter.doWait(WAITFOR_MSEC);
2333             // Stop the FGS.
2334             CommandReceiver.sendCommand(mContext,
2335                     CommandReceiver.COMMAND_STOP_FOREGROUND_SERVICE,
2336                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP2, 0, null);
2337             uid2Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE,
2338                     WatchUidRunner.STATE_CACHED_EMPTY);
2339 
2340             Thread.sleep(5000);
2341             // second BroadcastOptions.setTemporaryAppAllowlist() overlap with
2342             // first one.
2343             waiter = new WaitForBroadcast(mInstrumentation.getTargetContext());
2344             waiter.prepare(ACTION_START_FGS_RESULT);
2345             runWithShellPermissionIdentity(()-> {
2346                 final BroadcastOptions options = BroadcastOptions.makeBasic();
2347                 // setTemporaryAppAllowlist API requires
2348                 // START_FOREGROUND_SERVICES_FROM_BACKGROUND permission.
2349                 options.setTemporaryAppAllowlist(10000,
2350                         TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED, REASON_UNKNOWN,
2351                         "10seconds_br_options_2");
2352                 // Must use Shell to issue this command because Shell has
2353                 // START_FOREGROUND_SERVICES_FROM_BACKGROUND permission.
2354                 CommandReceiver.sendCommandWithBroadcastOptions(mContext,
2355                         CommandReceiver.COMMAND_START_FOREGROUND_SERVICE,
2356                         PACKAGE_NAME_APP1, PACKAGE_NAME_APP2, 0, null,
2357                         options.toBundle());
2358             });
2359             uid2Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_FG_SERVICE);
2360             waiter.doWait(WAITFOR_MSEC);
2361             // Stop the FGS.
2362             CommandReceiver.sendCommand(mContext,
2363                     CommandReceiver.COMMAND_STOP_FOREGROUND_SERVICE,
2364                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP2, 0, null);
2365             uid2Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE,
2366                     WatchUidRunner.STATE_CACHED_EMPTY);
2367 
2368             Thread.sleep(5000);
2369             // The first BroadcastOptions.setTemporaryAppAllowlist()'s 10000ms duration has expired.
2370             // Now FGS start is allowed by second BroadcastOption's 10000ms duration.
2371             waiter = new WaitForBroadcast(mInstrumentation.getTargetContext());
2372             waiter.prepare(ACTION_START_FGS_RESULT);
2373             CommandReceiver.sendCommand(mContext,
2374                     CommandReceiver.COMMAND_START_FOREGROUND_SERVICE,
2375                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP2, 0, null);
2376             uid2Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_FG_SERVICE);
2377             waiter.doWait(WAITFOR_MSEC);
2378             // Stop the FGS.
2379             CommandReceiver.sendCommand(mContext,
2380                     CommandReceiver.COMMAND_STOP_FOREGROUND_SERVICE,
2381                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP2, 0, null);
2382             uid2Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_CACHED_EMPTY);
2383         } finally {
2384             uid1Watcher.finish();
2385             uid2Watcher.finish();
2386             // Sleep 10 seconds to let the temp allowlist expire so it won't affect next test case.
2387             SystemClock.sleep(10000);
2388         }
2389     }
2390 
2391     /**
2392      * IActivityManager.startService() is called directly (does not go through
2393      * {@link Context#startForegroundService(Intent)}, a spoofed packageName "com.google.android.as"
2394      * is used as callingPackage. Although "com.google.android.as" is allowlisted to start
2395      * foreground service from the background, but framework will detect this is a spoofed
2396      * packageName and disallow foreground service start from the background.
2397      * @throws Exception
2398      */
2399     @Presubmit
2400     @Test
testSpoofPackageName()2401     public void testSpoofPackageName() throws Exception {
2402         ApplicationInfo app1Info = mContext.getPackageManager().getApplicationInfo(
2403                 PACKAGE_NAME_APP1, 0);
2404         WatchUidRunner uid1Watcher = new WatchUidRunner(mInstrumentation, app1Info.uid,
2405                 WAITFOR_MSEC);
2406         // CommandReceiver.COMMAND_START_FOREGROUND_SERVICE_SPOOF_PACKAGE_NAME needs access
2407         // to hidden API PackageManager.getAttentionServicePackageName() and
2408         // PackageManager.getSystemCaptionsServicePackageName(), so we need to call
2409         // hddenApiSettings.set("*") to exempt the hidden APIs.
2410         SettingsSession<String> hiddenApiSettings = new SettingsSession<>(
2411                 Settings.Global.getUriFor(
2412                         Settings.Global.HIDDEN_API_BLACKLIST_EXEMPTIONS),
2413                 Settings.Global::getString, Settings.Global::putString);
2414         hiddenApiSettings.set("*");
2415         try {
2416             // Enable the FGS background startForeground() restriction.
2417             enableFgsRestriction(true, true, null);
2418             // Start FGS in BG state.
2419             WaitForBroadcast waiter = new WaitForBroadcast(mInstrumentation.getTargetContext());
2420             waiter.prepare(ACTION_START_FGS_RESULT);
2421             CommandReceiver.sendCommand(mContext,
2422                     CommandReceiver.COMMAND_START_FOREGROUND_SERVICE_SPOOF_PACKAGE_NAME,
2423                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
2424             // APP1 does not enter FGS state
2425             try {
2426                 waiter.doWait(WAITFOR_MSEC);
2427                 fail("Service should not enter foreground service state");
2428             } catch (Exception e) {
2429             }
2430         } finally {
2431             uid1Watcher.finish();
2432             if (hiddenApiSettings != null) {
2433                 hiddenApiSettings.close();
2434             }
2435         }
2436     }
2437 
2438     @Test
testStartMediaPlaybackFromBg()2439     public void testStartMediaPlaybackFromBg() throws Exception {
2440         NotificationHelper notificationHelper = new NotificationHelper(mContext);
2441         ApplicationInfo app1Info = mContext.getPackageManager().getApplicationInfo(
2442                 PACKAGE_NAME_APP1, 0);
2443         WatchUidRunner uidWatcher = new WatchUidRunner(mInstrumentation, app1Info.uid,
2444                 WAITFOR_MSEC);
2445         // Grant notification listener access in order to query
2446         // MediaSessionManager.getActiveSessions().
2447         notificationHelper.enableListener(STUB_PACKAGE_NAME);
2448         try {
2449             // Enable the FGS background startForeground() restriction.
2450             enableFgsRestriction(true, true, null);
2451 
2452             final Bundle bundle = new Bundle();
2453             final CountDownLatch latch = new CountDownLatch(1);
2454             bundle.putParcelable(Intent.EXTRA_REMOTE_CALLBACK,
2455                     new RemoteCallback(result -> latch.countDown()));
2456             CommandReceiver.sendCommand(mContext,
2457                     CommandReceiver.COMMAND_CREATE_ACTIVE_MEDIA_SESSION,
2458                     PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0 /* flags */, bundle);
2459             if (!latch.await(WAITFOR_MSEC, TimeUnit.MILLISECONDS)) {
2460                 fail("Timed out waiting for the test app to receive the start_media_playback cmd");
2461             }
2462             uidWatcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_CACHED_EMPTY);
2463 
2464             final MediaSessionManager mediaSessionManager = mTargetContext.getSystemService(
2465                     MediaSessionManager.class);
2466             final List<MediaController> mediaControllers = mediaSessionManager.getActiveSessions(
2467                     new ComponentName(STUB_PACKAGE_NAME, TestNotificationListener.class.getName()));
2468             final MediaController controller = findMediaControllerForPkg(mediaControllers,
2469                     PACKAGE_NAME_APP1);
2470             // Send "play" command and verify that the app moves to FGS state.
2471             controller.getTransportControls().play();
2472             uidWatcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_FG_SERVICE);
2473             controller.getTransportControls().pause();
2474             uidWatcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_SERVICE);
2475             controller.getTransportControls().play();
2476             uidWatcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_FG_SERVICE);
2477 
2478             controller.getTransportControls().stop();
2479         } finally {
2480             notificationHelper.disableListener(STUB_PACKAGE_NAME);
2481             uidWatcher.finish();
2482             //DEFAULT_MEDIA_SESSION_CALLBACK_FGS_WHILE_IN_USE_TEMP_ALLOW_DURATION_MS = 10000ms
2483             SystemClock.sleep(10000);
2484         }
2485     }
2486 
findMediaControllerForPkg(List<MediaController> mediaControllers, String packageName)2487     private MediaController findMediaControllerForPkg(List<MediaController> mediaControllers,
2488             String packageName) {
2489         for (MediaController controller : mediaControllers) {
2490             if (packageName.equals(controller.getPackageName())) {
2491                 return controller;
2492             }
2493         }
2494         return null;
2495     }
2496 
2497     /**
2498      * Turn on the FGS BG-launch restriction. DeviceConfig can turn on restriction on the whole
2499      * device (across all apps). AppCompat can turn on restriction on a single app package.
2500      *
2501      * @param enable          true to turn on restriction, false to turn off.
2502      * @param useDeviceConfig true to use DeviceConfig, false to use AppCompat CHANGE ID.
2503      * @param packageName     the packageName if using AppCompat CHANGE ID.
2504      */
enableFgsRestriction(boolean enable, boolean useDeviceConfig, String packageName)2505     private void enableFgsRestriction(boolean enable, boolean useDeviceConfig, String packageName)
2506             throws Exception {
2507         if (useDeviceConfig) {
2508             runWithShellPermissionIdentity(() -> {
2509                         DeviceConfig.setProperty("activity_manager",
2510                                 KEY_DEFAULT_FGS_STARTS_RESTRICTION_ENABLED,
2511                                 Boolean.toString(enable), false);
2512                     }
2513             );
2514         } else {
2515             CtsAppTestUtils.executeShellCmd(mInstrumentation,
2516                     "am compat " + (enable ? "enable" : "disable")
2517                             + " FGS_BG_START_RESTRICTION_CHANGE_ID " + packageName);
2518         }
2519     }
2520 
2521     /**
2522      * Clean up the FGS BG-launch restriction.
2523      *
2524      * @param packageName the packageName that will have its changeid override reset.
2525      */
resetFgsRestriction(String packageName)2526     private void resetFgsRestriction(String packageName)
2527             throws Exception {
2528         CtsAppTestUtils.executeShellCmd(mInstrumentation,
2529                 "am compat reset FGS_BG_START_RESTRICTION_CHANGE_ID " + packageName);
2530     }
2531 
2532     /**
2533      * SYSTEM_ALERT_WINDOW permission will allow both BG-activity start and BG-FGS start.
2534      * Some cases we want to grant this permission to allow activity start to bring the app up to
2535      * TOP state.
2536      * Some cases we want to revoke this permission to test other BG-FGS-launch exemptions.
2537      */
allowBgActivityStart(String packageName, boolean allow)2538     private void allowBgActivityStart(String packageName, boolean allow) throws Exception {
2539         if (allow) {
2540             PermissionUtils.grantPermission(
2541                     packageName, android.Manifest.permission.SYSTEM_ALERT_WINDOW);
2542         } else {
2543             PermissionUtils.revokePermission(
2544                     packageName, android.Manifest.permission.SYSTEM_ALERT_WINDOW);
2545         }
2546     }
2547 
setFgsStartForegroundTimeout(int timeoutMs)2548     private void setFgsStartForegroundTimeout(int timeoutMs) throws Exception {
2549         runWithShellPermissionIdentity(() -> {
2550                     DeviceConfig.setProperty("activity_manager",
2551                             KEY_FGS_START_FOREGROUND_TIMEOUT,
2552                             Integer.toString(timeoutMs), false);
2553                 }
2554         );
2555     }
2556 
setAppOp(String packageName, String opStr, boolean allow)2557     private void setAppOp(String packageName, String opStr, boolean allow) throws Exception {
2558         CtsAppTestUtils.executeShellCmd(mInstrumentation,
2559                 "appops set " + packageName + " " + opStr + " "
2560                         + (allow ? "allow" : "deny"));
2561     }
2562 
setPushMessagingOverQuotaBehavior( int type)2563     private void setPushMessagingOverQuotaBehavior(
2564             /* @PowerExemptionManager.TempAllowListType */ int type) throws Exception {
2565         runWithShellPermissionIdentity(() -> {
2566                     DeviceConfig.setProperty("activity_manager",
2567                             KEY_PUSH_MESSAGING_OVER_QUOTA_BEHAVIOR,
2568                             Integer.toString(type), false);
2569                 }
2570         );
2571         // Sleep 2 seconds to allow the device config change to be applied.
2572         SystemClock.sleep(2000);
2573     }
2574 
getPushMessagingOverQuotaBehavior()2575     private int getPushMessagingOverQuotaBehavior() throws Exception {
2576         final String defaultBehaviorStr = CtsAppTestUtils.executeShellCmd(mInstrumentation,
2577                 "device_config get activity_manager "
2578                         + KEY_PUSH_MESSAGING_OVER_QUOTA_BEHAVIOR).trim();
2579         int defaultBehavior = TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED;
2580         if (!defaultBehaviorStr.equals("null")) {
2581             try {
2582                 defaultBehavior = Integer.parseInt(defaultBehaviorStr);
2583             } catch (NumberFormatException e) {
2584                 Log.e("ActivityManagerFgsBgStartTest",
2585                         "getPushMessagingOverQuotaBehavior:", e);
2586             }
2587         }
2588         return defaultBehavior;
2589     }
2590 
enableFgsSawRestriction(boolean enable, String packageName)2591     private void enableFgsSawRestriction(boolean enable, String packageName)
2592             throws Exception {
2593         runWithShellPermissionIdentity(() -> {
2594                     DeviceConfig.setProperty("activity_manager",
2595                             "fgs_saw_restrictions_enabled",
2596                             Boolean.toString(enable), false);
2597                 }
2598         );
2599         final String action = enable ? "enable" : "disable";
2600         CtsAppTestUtils.executeShellCmd(mInstrumentation, "am compat " + action
2601                 + " --no-kill FGS_SAW_RESTRICTIONS " + packageName);
2602     }
2603 
resetFgsSawRestrictionEnabled(String packageName)2604     private void resetFgsSawRestrictionEnabled(String packageName) {
2605         mInstrumentation.getUiAutomation().executeShellCommand(
2606                 "am compat reset --no-kill FGS_SAW_RESTRICTIONS " + packageName);
2607     }
2608 }
2609