1 /*
2  * Copyright (C) 2022 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 com.android.server.am;
18 
19 import static android.Manifest.permission.ACCESS_BACKGROUND_LOCATION;
20 import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
21 import static android.Manifest.permission.ACCESS_FINE_LOCATION;
22 import static android.Manifest.permission.CAMERA;
23 import static android.Manifest.permission.RECORD_AUDIO;
24 import static android.app.ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
25 import static android.app.ActivityManager.PROCESS_STATE_TOP;
26 import static android.app.ActivityManager.RESTRICTION_LEVEL_ADAPTIVE_BUCKET;
27 import static android.app.ActivityManager.RESTRICTION_LEVEL_BACKGROUND_RESTRICTED;
28 import static android.app.ActivityManager.RESTRICTION_LEVEL_EXEMPTED;
29 import static android.app.ActivityManager.RESTRICTION_LEVEL_RESTRICTED_BUCKET;
30 import static android.app.ActivityManager.isLowRamDeviceStatic;
31 import static android.app.AppOpsManager.MODE_ALLOWED;
32 import static android.app.AppOpsManager.MODE_IGNORED;
33 import static android.app.AppOpsManager.OP_ACTIVATE_PLATFORM_VPN;
34 import static android.app.AppOpsManager.OP_ACTIVATE_VPN;
35 import static android.app.AppOpsManager.OP_CAMERA;
36 import static android.app.AppOpsManager.OP_FINE_LOCATION;
37 import static android.app.AppOpsManager.OP_NONE;
38 import static android.app.AppOpsManager.OP_RECORD_AUDIO;
39 import static android.app.AppOpsManager.OP_SYSTEM_EXEMPT_FROM_POWER_RESTRICTIONS;
40 import static android.app.usage.UsageStatsManager.REASON_MAIN_DEFAULT;
41 import static android.app.usage.UsageStatsManager.REASON_MAIN_FORCED_BY_SYSTEM;
42 import static android.app.usage.UsageStatsManager.REASON_MAIN_FORCED_BY_USER;
43 import static android.app.usage.UsageStatsManager.REASON_MAIN_MASK;
44 import static android.app.usage.UsageStatsManager.REASON_MAIN_USAGE;
45 import static android.app.usage.UsageStatsManager.REASON_SUB_DEFAULT_UNDEFINED;
46 import static android.app.usage.UsageStatsManager.REASON_SUB_FORCED_SYSTEM_FLAG_ABUSE;
47 import static android.app.usage.UsageStatsManager.REASON_SUB_FORCED_USER_FLAG_INTERACTION;
48 import static android.app.usage.UsageStatsManager.REASON_SUB_MASK;
49 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_USER_INTERACTION;
50 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_ACTIVE;
51 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_EXEMPTED;
52 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_FREQUENT;
53 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_NEVER;
54 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RARE;
55 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RESTRICTED;
56 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_WORKING_SET;
57 import static android.content.pm.PackageManager.PERMISSION_DENIED;
58 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
59 import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA;
60 import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION;
61 import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK;
62 import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE;
63 import static android.os.PowerExemptionManager.REASON_CARRIER_PRIVILEGED_APP;
64 import static android.os.PowerExemptionManager.REASON_DENIED;
65 
66 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
67 
68 import static com.android.internal.notification.SystemNotificationChannels.ABUSIVE_BACKGROUND_APPS;
69 import static com.android.server.am.AppBatteryTracker.AppBatteryPolicy.getFloatArray;
70 import static com.android.server.am.AppBatteryTracker.BatteryUsage.BATTERY_USAGE_INDEX_BACKGROUND;
71 import static com.android.server.am.AppBatteryTracker.BatteryUsage.BATTERY_USAGE_INDEX_CACHED;
72 import static com.android.server.am.AppBatteryTracker.BatteryUsage.BATTERY_USAGE_INDEX_FOREGROUND;
73 import static com.android.server.am.AppBatteryTracker.BatteryUsage.BATTERY_USAGE_INDEX_FOREGROUND_SERVICE;
74 import static com.android.server.am.AppBatteryTracker.BatteryUsage.BATT_DIMENS;
75 import static com.android.server.am.AppPermissionTracker.AppPermissionPolicy;
76 import static com.android.server.am.AppRestrictionController.STOCK_PM_FLAGS;
77 import static com.android.server.am.BaseAppStateTracker.STATE_TYPE_FGS_LOCATION;
78 import static com.android.server.am.BaseAppStateTracker.STATE_TYPE_FGS_MEDIA_PLAYBACK;
79 import static com.android.server.am.BaseAppStateTracker.STATE_TYPE_FGS_WITH_NOTIFICATION;
80 import static com.android.server.am.BaseAppStateTracker.STATE_TYPE_MEDIA_SESSION;
81 import static com.android.server.am.BaseAppStateTracker.STATE_TYPE_PERMISSION;
82 
83 import static org.junit.Assert.assertEquals;
84 import static org.junit.Assert.assertTrue;
85 import static org.junit.Assert.fail;
86 import static org.mockito.ArgumentMatchers.any;
87 import static org.mockito.ArgumentMatchers.eq;
88 import static org.mockito.Mockito.anyBoolean;
89 import static org.mockito.Mockito.anyInt;
90 import static org.mockito.Mockito.anyLong;
91 import static org.mockito.Mockito.anyObject;
92 import static org.mockito.Mockito.anyString;
93 import static org.mockito.Mockito.atLeast;
94 import static org.mockito.Mockito.clearInvocations;
95 import static org.mockito.Mockito.doAnswer;
96 import static org.mockito.Mockito.doReturn;
97 import static org.mockito.Mockito.mock;
98 import static org.mockito.Mockito.never;
99 import static org.mockito.Mockito.spy;
100 import static org.mockito.Mockito.timeout;
101 import static org.mockito.Mockito.times;
102 import static org.mockito.Mockito.verify;
103 
104 import android.annotation.UserIdInt;
105 import android.app.ActivityManagerInternal;
106 import android.app.ActivityManagerInternal.AppBackgroundRestrictionListener;
107 import android.app.ActivityManagerInternal.BindServiceEventListener;
108 import android.app.ActivityManagerInternal.BroadcastEventListener;
109 import android.app.AppOpsManager;
110 import android.app.IActivityManager;
111 import android.app.IUidObserver;
112 import android.app.Notification;
113 import android.app.NotificationManager;
114 import android.app.role.RoleManager;
115 import android.app.usage.AppStandbyInfo;
116 import android.content.Context;
117 import android.content.Intent;
118 import android.content.pm.PackageManager;
119 import android.content.pm.PackageManagerInternal;
120 import android.media.session.MediaController;
121 import android.media.session.MediaSession;
122 import android.media.session.MediaSessionManager;
123 import android.media.session.MediaSessionManager.OnActiveSessionsChangedListener;
124 import android.os.BatteryManagerInternal;
125 import android.os.BatteryStatsInternal;
126 import android.os.BatteryUsageStats;
127 import android.os.Handler;
128 import android.os.MessageQueue;
129 import android.os.Process;
130 import android.os.RemoteException;
131 import android.os.SystemClock;
132 import android.os.UidBatteryConsumer;
133 import android.os.UserHandle;
134 import android.permission.PermissionManager;
135 import android.provider.DeviceConfig;
136 import android.service.notification.StatusBarNotification;
137 import android.telephony.TelephonyManager;
138 import android.telephony.TelephonyManager.CarrierPrivilegesCallback;
139 import android.util.Log;
140 import android.util.Pair;
141 import android.util.SparseArray;
142 
143 import androidx.test.runner.AndroidJUnit4;
144 
145 import com.android.internal.R;
146 import com.android.internal.app.IAppOpsService;
147 import com.android.server.AppStateTracker;
148 import com.android.server.DeviceIdleInternal;
149 import com.android.server.am.AppBatteryExemptionTracker.AppBatteryExemptionPolicy;
150 import com.android.server.am.AppBatteryExemptionTracker.UidBatteryStates;
151 import com.android.server.am.AppBatteryExemptionTracker.UidStateEventWithBattery;
152 import com.android.server.am.AppBatteryTracker.AppBatteryPolicy;
153 import com.android.server.am.AppBatteryTracker.ImmutableBatteryUsage;
154 import com.android.server.am.AppBindServiceEventsTracker.AppBindServiceEventsPolicy;
155 import com.android.server.am.AppBroadcastEventsTracker.AppBroadcastEventsPolicy;
156 import com.android.server.am.AppFGSTracker.AppFGSPolicy;
157 import com.android.server.am.AppMediaSessionTracker.AppMediaSessionPolicy;
158 import com.android.server.am.AppRestrictionController.ConstantsObserver;
159 import com.android.server.am.AppRestrictionController.NotificationHelper;
160 import com.android.server.am.AppRestrictionController.RestrictionSettings;
161 import com.android.server.am.AppRestrictionController.UidBatteryUsageProvider;
162 import com.android.server.am.BaseAppStateTimeEvents.BaseTimeEvent;
163 import com.android.server.apphibernation.AppHibernationManagerInternal;
164 import com.android.server.notification.NotificationManagerInternal;
165 import com.android.server.pm.UserManagerInternal;
166 import com.android.server.pm.permission.PermissionManagerServiceInternal;
167 import com.android.server.usage.AppStandbyInternal;
168 import com.android.server.usage.AppStandbyInternal.AppIdleStateChangeListener;
169 
170 import org.junit.After;
171 import org.junit.Before;
172 import org.junit.Test;
173 import org.junit.runner.RunWith;
174 import org.mockito.ArgumentCaptor;
175 import org.mockito.Captor;
176 import org.mockito.Mock;
177 import org.mockito.MockitoAnnotations;
178 import org.mockito.verification.VerificationMode;
179 
180 import java.io.File;
181 import java.time.Duration;
182 import java.util.ArrayList;
183 import java.util.Arrays;
184 import java.util.Collections;
185 import java.util.LinkedList;
186 import java.util.List;
187 import java.util.Set;
188 import java.util.concurrent.CountDownLatch;
189 import java.util.concurrent.Executor;
190 import java.util.concurrent.TimeUnit;
191 import java.util.concurrent.TimeoutException;
192 import java.util.function.BiConsumer;
193 import java.util.stream.Collectors;
194 
195 /**
196  * Tests for {@link AppRestrictionController}.
197  *
198  * Build/Install/Run:
199  *  atest FrameworksMockingServicesTests:BackgroundRestrictionTest
200  */
201 @RunWith(AndroidJUnit4.class)
202 public final class BackgroundRestrictionTest {
203     private static final String TAG = BackgroundRestrictionTest.class.getSimpleName();
204 
205     private static final int TEST_USER0 = UserHandle.USER_SYSTEM;
206     private static final int TEST_USER1 = UserHandle.MIN_SECONDARY_USER_ID;
207     private static final int[] TEST_USERS = new int[] {TEST_USER0, TEST_USER1};
208     private static final String TEST_PACKAGE_BASE = "test_";
209     private static final int TEST_PACKAGE_APPID_BASE = Process.FIRST_APPLICATION_UID;
210     private static final int[] TEST_PACKAGE_USER0_UIDS = new int[] {
211         UserHandle.getUid(TEST_USER0, TEST_PACKAGE_APPID_BASE + 0),
212         UserHandle.getUid(TEST_USER0, TEST_PACKAGE_APPID_BASE + 1),
213         UserHandle.getUid(TEST_USER0, TEST_PACKAGE_APPID_BASE + 2),
214         UserHandle.getUid(TEST_USER0, TEST_PACKAGE_APPID_BASE + 3),
215         UserHandle.getUid(TEST_USER0, TEST_PACKAGE_APPID_BASE + 4),
216         UserHandle.getUid(TEST_USER0, TEST_PACKAGE_APPID_BASE + 5),
217         UserHandle.getUid(TEST_USER0, TEST_PACKAGE_APPID_BASE + 6),
218     };
219     private static final int[] TEST_PACKAGE_USER1_UIDS = new int[] {
220         UserHandle.getUid(TEST_USER1, TEST_PACKAGE_APPID_BASE + 0),
221         UserHandle.getUid(TEST_USER1, TEST_PACKAGE_APPID_BASE + 1),
222         UserHandle.getUid(TEST_USER1, TEST_PACKAGE_APPID_BASE + 2),
223         UserHandle.getUid(TEST_USER1, TEST_PACKAGE_APPID_BASE + 3),
224         UserHandle.getUid(TEST_USER1, TEST_PACKAGE_APPID_BASE + 4),
225         UserHandle.getUid(TEST_USER1, TEST_PACKAGE_APPID_BASE + 5),
226         UserHandle.getUid(TEST_USER1, TEST_PACKAGE_APPID_BASE + 6),
227     };
228     private static final int[][] TEST_UIDS = new int[][] {
229         TEST_PACKAGE_USER0_UIDS,
230         TEST_PACKAGE_USER1_UIDS,
231     };
232     private static final int[] TEST_STANDBY_BUCKETS = new int[] {
233         STANDBY_BUCKET_EXEMPTED,
234         STANDBY_BUCKET_ACTIVE,
235         STANDBY_BUCKET_WORKING_SET,
236         STANDBY_BUCKET_FREQUENT,
237         STANDBY_BUCKET_RARE,
238         STANDBY_BUCKET_RESTRICTED,
239         STANDBY_BUCKET_NEVER,
240     };
241 
242     private static final int BATTERY_FULL_CHARGE_MAH = 5_000;
243 
244     private static final String[] MOCK_PRIVILEGED_PACKAGES_0 = new String[] {
245         TEST_PACKAGE_BASE + 0,
246         TEST_PACKAGE_BASE + 1,
247     };
248     private static final String[] MOCK_PRIVILEGED_PACKAGES_1 = new String[] {
249         TEST_PACKAGE_BASE + 2,
250         TEST_PACKAGE_BASE + 3,
251     };
252     private static final String[] MOCK_PRIVILEGED_PACKAGES_2 = new String[] {
253         TEST_PACKAGE_BASE + 4,
254         TEST_PACKAGE_BASE + 5,
255     };
256     private static final int[] MOCK_PRIVILEGED_UIDS_0 = new int[] {
257         UserHandle.getUid(TEST_USER0, TEST_PACKAGE_APPID_BASE + 0),
258         UserHandle.getUid(TEST_USER0, TEST_PACKAGE_APPID_BASE + 1),
259     };
260     private static final int[] MOCK_PRIVILEGED_UIDS_1 = new int[] {
261         UserHandle.getUid(TEST_USER0, TEST_PACKAGE_APPID_BASE + 2),
262         UserHandle.getUid(TEST_USER0, TEST_PACKAGE_APPID_BASE + 3),
263     };
264     private static final int[] MOCK_PRIVILEGED_UIDS_2 = new int[] {
265         UserHandle.getUid(TEST_USER0, TEST_PACKAGE_APPID_BASE + 4),
266         UserHandle.getUid(TEST_USER0, TEST_PACKAGE_APPID_BASE + 5),
267     };
268     private static final String[][] MOCK_PRIVILEGED_PACKAGES = new String[][] {
269         MOCK_PRIVILEGED_PACKAGES_0,
270         MOCK_PRIVILEGED_PACKAGES_1,
271     };
272     private static final int[][] MOCK_PRIVILEGED_UIDS = new int[][] {
273         MOCK_PRIVILEGED_UIDS_0,
274         MOCK_PRIVILEGED_UIDS_1,
275     };
276 
277     @Mock private ActivityManagerInternal mActivityManagerInternal;
278     @Mock private ActivityManagerService mActivityManagerService;
279     @Mock private ActivityManagerConstants mActivityManagerConstants;
280     @Mock private AppOpsManager mAppOpsManager;
281     @Mock private AppStandbyInternal mAppStandbyInternal;
282     @Mock private AppHibernationManagerInternal mAppHibernationInternal;
283     @Mock private AppStateTracker mAppStateTracker;
284     @Mock private BatteryManagerInternal mBatteryManagerInternal;
285     @Mock private BatteryStatsInternal mBatteryStatsInternal;
286     @Mock private DeviceIdleInternal mDeviceIdleInternal;
287     @Mock private IActivityManager mIActivityManager;
288     @Mock private UserManagerInternal mUserManagerInternal;
289     @Mock private PackageManager mPackageManager;
290     @Mock private PackageManagerInternal mPackageManagerInternal;
291     @Mock private NotificationManager mNotificationManager;
292     @Mock private NotificationManagerInternal mNotificationManagerInternal;
293     @Mock private PermissionManager mPermissionManager;
294     @Mock private PermissionManagerServiceInternal mPermissionManagerServiceInternal;
295     @Mock private MediaSessionManager mMediaSessionManager;
296     @Mock private RoleManager mRoleManager;
297     @Mock private TelephonyManager mTelephonyManager;
298     @Mock private IAppOpsService mIAppOpsService;
299 
300     private PhoneCarrierPrivileges mPhoneCarrierPrivileges;
301 
302     private long mCurrentTimeMillis;
303 
304     @Captor private ArgumentCaptor<AppStateTracker.BackgroundRestrictedAppListener> mFasListenerCap;
305     private AppStateTracker.BackgroundRestrictedAppListener mFasListener;
306 
307     @Captor private ArgumentCaptor<AppIdleStateChangeListener> mIdleStateListenerCap;
308     private AppIdleStateChangeListener mIdleStateListener;
309 
310     @Captor private ArgumentCaptor<IUidObserver> mUidObserversCap;
311     private IUidObserver mUidObservers;
312 
313     @Captor private ArgumentCaptor<OnActiveSessionsChangedListener> mActiveSessionListenerCap;
314     private OnActiveSessionsChangedListener mActiveSessionListener;
315 
316     @Captor private ArgumentCaptor<BroadcastEventListener> mBroadcastEventListenerCap;
317     private BroadcastEventListener mBroadcastEventListener;
318 
319     @Captor private ArgumentCaptor<BindServiceEventListener> mBindServiceEventListenerCap;
320     private BindServiceEventListener mBindServiceEventListener;
321 
322     private Context mContext = getInstrumentation().getTargetContext();
323     private TestBgRestrictionInjector mInjector;
324     private AppRestrictionController mBgRestrictionController;
325     private AppBatteryTracker mAppBatteryTracker;
326     private AppBatteryPolicy mAppBatteryPolicy;
327     private AppBatteryExemptionTracker mAppBatteryExemptionTracker;
328     private AppBroadcastEventsTracker mAppBroadcastEventsTracker;
329     private AppBindServiceEventsTracker mAppBindServiceEventsTracker;
330     private AppFGSTracker mAppFGSTracker;
331     private AppMediaSessionTracker mAppMediaSessionTracker;
332     private AppPermissionTracker mAppPermissionTracker;
333 
334     @Before
setUp()335     public void setUp() throws Exception {
336         MockitoAnnotations.initMocks(this);
337         initController();
338     }
339 
initController()340     private void initController() throws Exception {
341         mInjector = spy(new TestBgRestrictionInjector(mContext));
342         mBgRestrictionController = spy(new AppRestrictionController(mInjector,
343                     mActivityManagerService));
344 
345         mActivityManagerService.mConstants = mActivityManagerConstants;
346         mPhoneCarrierPrivileges = new PhoneCarrierPrivileges(
347                 mInjector.getTelephonyManager(), MOCK_PRIVILEGED_PACKAGES.length);
348         for (int i = 0; i < MOCK_PRIVILEGED_PACKAGES.length; i++) {
349             mPhoneCarrierPrivileges.addNewPrivilegePackages(i,
350                     MOCK_PRIVILEGED_PACKAGES[i], MOCK_PRIVILEGED_UIDS[i]);
351         }
352 
353         doReturn(PROCESS_STATE_FOREGROUND_SERVICE).when(mActivityManagerInternal)
354                 .getUidProcessState(anyInt());
355         doReturn(TEST_USERS).when(mUserManagerInternal).getUserIds();
356         for (int userId: TEST_USERS) {
357             final ArrayList<AppStandbyInfo> appStandbyInfoList = new ArrayList<>();
358             for (int i = 0; i < TEST_STANDBY_BUCKETS.length; i++) {
359                 final String packageName = TEST_PACKAGE_BASE + i;
360                 final int uid = UserHandle.getUid(userId, TEST_PACKAGE_APPID_BASE + i);
361                 appStandbyInfoList.add(new AppStandbyInfo(packageName, TEST_STANDBY_BUCKETS[i]));
362                 doReturn(uid)
363                         .when(mPackageManagerInternal)
364                         .getPackageUid(packageName, STOCK_PM_FLAGS, userId);
365                 doReturn(false)
366                         .when(mAppStateTracker)
367                         .isAppBackgroundRestricted(uid, packageName);
368                 doReturn(TEST_STANDBY_BUCKETS[i])
369                         .when(mAppStandbyInternal)
370                         .getAppStandbyBucket(eq(packageName), eq(userId), anyLong(), anyBoolean());
371                 doReturn(new String[]{packageName})
372                         .when(mPackageManager)
373                         .getPackagesForUid(eq(uid));
374                 final int[] ops = new int[] {
375                     OP_ACTIVATE_VPN,
376                     OP_ACTIVATE_PLATFORM_VPN,
377                     OP_FINE_LOCATION,
378                     OP_CAMERA,
379                     OP_RECORD_AUDIO,
380                     OP_SYSTEM_EXEMPT_FROM_POWER_RESTRICTIONS,
381                 };
382                 for (int op : ops) {
383                     setAppOpState(packageName, uid, op, false);
384                 }
385                 final String[] permissions = new String[] {ACCESS_BACKGROUND_LOCATION,
386                         ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION, CAMERA, RECORD_AUDIO,
387                 };
388                 for (String permission : permissions) {
389                     setPermissionState(packageName, uid, permission, false);
390                 }
391             }
392             doReturn(appStandbyInfoList).when(mAppStandbyInternal).getAppStandbyBuckets(userId);
393         }
394 
395         doReturn(BATTERY_FULL_CHARGE_MAH * 1000).when(mBatteryManagerInternal)
396                 .getBatteryFullCharge();
397 
398         mBgRestrictionController.onSystemReady();
399 
400         verify(mInjector.getAppStateTracker())
401                 .addBackgroundRestrictedAppListener(mFasListenerCap.capture());
402         mFasListener = mFasListenerCap.getValue();
403         verify(mInjector.getAppStandbyInternal())
404                 .addListener(mIdleStateListenerCap.capture());
405         mIdleStateListener = mIdleStateListenerCap.getValue();
406         verify(mInjector.getIActivityManager())
407                 .registerUidObserver(mUidObserversCap.capture(),
408                     anyInt(), anyInt(), anyString());
409         mUidObservers = mUidObserversCap.getValue();
410         verify(mAppMediaSessionTracker.mInjector.getMediaSessionManager())
411                 .addOnActiveSessionsChangedListener(any(), any(), any(),
412                         mActiveSessionListenerCap.capture());
413         mActiveSessionListener = mActiveSessionListenerCap.getValue();
414         verify(mAppBroadcastEventsTracker.mInjector.getActivityManagerInternal())
415                 .addBroadcastEventListener(mBroadcastEventListenerCap.capture());
416         mBroadcastEventListener = mBroadcastEventListenerCap.getValue();
417         verify(mAppBindServiceEventsTracker.mInjector.getActivityManagerInternal())
418                 .addBindServiceEventListener(mBindServiceEventListenerCap.capture());
419         mBindServiceEventListener = mBindServiceEventListenerCap.getValue();
420         waitForIdleHandler(mBgRestrictionController.getBackgroundHandler());
421     }
422 
423     @After
tearDown()424     public void tearDown() {
425         mBgRestrictionController.tearDown();
426         mBgRestrictionController.getBackgroundHandlerThread().quitSafely();
427     }
428 
429     @Test
testInitialLevels()430     public void testInitialLevels() throws Exception {
431         final int[] expectedLevels = {
432             RESTRICTION_LEVEL_EXEMPTED,
433             RESTRICTION_LEVEL_ADAPTIVE_BUCKET,
434             RESTRICTION_LEVEL_ADAPTIVE_BUCKET,
435             RESTRICTION_LEVEL_ADAPTIVE_BUCKET,
436             RESTRICTION_LEVEL_ADAPTIVE_BUCKET,
437             RESTRICTION_LEVEL_RESTRICTED_BUCKET,
438             RESTRICTION_LEVEL_BACKGROUND_RESTRICTED,
439         };
440         for (int i = 0; i < TEST_UIDS.length; i++) {
441             final int[] uids = TEST_UIDS[i];
442             for (int j = 0; j < uids.length; j++) {
443                 assertEquals(expectedLevels[j],
444                         mBgRestrictionController.getRestrictionLevel(uids[j]));
445                 assertEquals(expectedLevels[j],
446                         mBgRestrictionController.getRestrictionLevel(uids[j],
447                                 TEST_PACKAGE_BASE + j));
448             }
449         }
450     }
451 
452     @Test
testTogglingBackgroundRestrict()453     public void testTogglingBackgroundRestrict() throws Exception {
454         DeviceConfigSession<Boolean> bgAutoRestrictedBucketOnBgRestriction = null;
455         try {
456             bgAutoRestrictedBucketOnBgRestriction = new DeviceConfigSession<>(
457                     DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
458                     ConstantsObserver.KEY_BG_AUTO_RESTRICTED_BUCKET_ON_BG_RESTRICTION,
459                     DeviceConfig::getBoolean,
460                     ConstantsObserver.DEFAULT_BG_AUTO_RESTRICTED_BUCKET_ON_BG_RESTRICTION);
461             bgAutoRestrictedBucketOnBgRestriction.set(true);
462 
463             testTogglingBackgroundRestrictInternal();
464         } finally {
465             closeIfNotNull(bgAutoRestrictedBucketOnBgRestriction);
466         }
467     }
468 
testTogglingBackgroundRestrictInternal()469     private void testTogglingBackgroundRestrictInternal() throws Exception {
470         final int testPkgIndex = 2;
471         final String testPkgName = TEST_PACKAGE_BASE + testPkgIndex;
472         final int testUser = TEST_USER0;
473         final int testUid = UserHandle.getUid(testUser, TEST_PACKAGE_APPID_BASE + testPkgIndex);
474         final TestAppRestrictionLevelListener listener = new TestAppRestrictionLevelListener();
475         final long timeout = 1_000; // ms
476 
477         mBgRestrictionController.addAppBackgroundRestrictionListener(listener);
478 
479         setBackgroundRestrict(testPkgName, testUid, false, listener);
480 
481         // Verify the current settings.
482         verifyRestrictionLevel(RESTRICTION_LEVEL_ADAPTIVE_BUCKET, testPkgName, testUid);
483         assertEquals(STANDBY_BUCKET_WORKING_SET, mInjector.getAppStandbyInternal()
484                 .getAppStandbyBucket(testPkgName, testUser, SystemClock.elapsedRealtime(), false));
485 
486         // Now toggling ON the background restrict.
487         setBackgroundRestrict(testPkgName, testUid, true, listener);
488 
489         // We should have been in the background restricted level.
490         verifyRestrictionLevel(RESTRICTION_LEVEL_BACKGROUND_RESTRICTED, testPkgName, testUid);
491 
492         listener.verify(timeout, testUid, testPkgName, RESTRICTION_LEVEL_BACKGROUND_RESTRICTED);
493 
494         // The app should have been put into the restricted standby bucket.
495         verify(mInjector.getAppStandbyInternal(), atLeast(1)).restrictApp(
496                 eq(testPkgName),
497                 eq(testUser),
498                 eq(REASON_MAIN_FORCED_BY_USER),
499                 eq(REASON_SUB_FORCED_USER_FLAG_INTERACTION));
500 
501         // Changing to the restricted standby bucket won't make a difference.
502         listener.mLatchHolder[0] = new CountDownLatch(1);
503         mIdleStateListener.onAppIdleStateChanged(testPkgName, testUser, false,
504                 STANDBY_BUCKET_RESTRICTED, REASON_MAIN_USAGE);
505         waitForIdleHandler(mBgRestrictionController.getBackgroundHandler());
506         verifyRestrictionLevel(RESTRICTION_LEVEL_BACKGROUND_RESTRICTED, testPkgName, testUid);
507         try {
508             listener.verify(timeout, testUid, testPkgName, RESTRICTION_LEVEL_BACKGROUND_RESTRICTED);
509             fail("There shouldn't be any level change events");
510         } catch (Exception e) {
511             // Expected.
512         }
513 
514         clearInvocations(mInjector.getAppStandbyInternal());
515 
516         // Toggling back.
517         setBackgroundRestrict(testPkgName, testUid, false, listener);
518 
519         // It should have gone back to adaptive level.
520         verifyRestrictionLevel(RESTRICTION_LEVEL_ADAPTIVE_BUCKET, testPkgName, testUid);
521 
522         // The app standby bucket should be the rare.
523         verify(mInjector.getAppStandbyInternal(), atLeast(1)).maybeUnrestrictApp(
524                 eq(testPkgName),
525                 eq(testUser),
526                 eq(REASON_MAIN_FORCED_BY_USER),
527                 eq(REASON_SUB_FORCED_USER_FLAG_INTERACTION),
528                 eq(REASON_MAIN_USAGE),
529                 eq(REASON_SUB_USAGE_USER_INTERACTION));
530 
531         listener.verify(timeout, testUid, testPkgName, RESTRICTION_LEVEL_ADAPTIVE_BUCKET);
532 
533         clearInvocations(mInjector.getAppStandbyInternal());
534 
535         // Now set its UID state active.
536         mUidObservers.onUidActive(testUid);
537 
538         // Now toggling ON the background restrict.
539         setBackgroundRestrict(testPkgName, testUid, true, listener);
540 
541         // We should have been in the background restricted level.
542         verifyRestrictionLevel(RESTRICTION_LEVEL_BACKGROUND_RESTRICTED, testPkgName, testUid);
543 
544         listener.verify(timeout, testUid, testPkgName, RESTRICTION_LEVEL_BACKGROUND_RESTRICTED);
545 
546         // The app should have NOT been put into the restricted standby bucket.
547         verify(mInjector.getAppStandbyInternal(), never()).restrictApp(
548                 eq(testPkgName),
549                 eq(testUser),
550                 eq(REASON_MAIN_FORCED_BY_USER),
551                 eq(REASON_SUB_FORCED_USER_FLAG_INTERACTION));
552 
553         // Now set its UID to idle.
554         mUidObservers.onUidIdle(testUid, false);
555 
556         // The app should have been put into the restricted standby bucket because we're idle now.
557         verify(mInjector.getAppStandbyInternal(), timeout(timeout).times(1)).restrictApp(
558                 eq(testPkgName),
559                 eq(testUser),
560                 eq(REASON_MAIN_FORCED_BY_USER),
561                 eq(REASON_SUB_FORCED_USER_FLAG_INTERACTION));
562     }
563 
564     @Test
testTogglingStandbyBucket()565     public void testTogglingStandbyBucket() throws Exception {
566         final int testPkgIndex = 2;
567         final String testPkgName = TEST_PACKAGE_BASE + testPkgIndex;
568         final int testUser = TEST_USER0;
569         final int testUid = UserHandle.getUid(testUser, TEST_PACKAGE_APPID_BASE + testPkgIndex);
570         final TestAppRestrictionLevelListener listener = new TestAppRestrictionLevelListener();
571         final long timeout = 1_000; // ms
572 
573         mBgRestrictionController.addAppBackgroundRestrictionListener(listener);
574 
575         setBackgroundRestrict(testPkgName, testUid, false, listener);
576 
577         // Verify the current settings.
578         verifyRestrictionLevel(RESTRICTION_LEVEL_ADAPTIVE_BUCKET, testPkgName, testUid);
579 
580         for (int bucket: Arrays.asList(STANDBY_BUCKET_ACTIVE, STANDBY_BUCKET_WORKING_SET,
581                 STANDBY_BUCKET_FREQUENT, STANDBY_BUCKET_RARE)) {
582             listener.mLatchHolder[0] = new CountDownLatch(1);
583             mIdleStateListener.onAppIdleStateChanged(testPkgName, testUser, false,
584                     bucket, REASON_MAIN_USAGE);
585             waitForIdleHandler(mBgRestrictionController.getBackgroundHandler());
586             verifyRestrictionLevel(RESTRICTION_LEVEL_ADAPTIVE_BUCKET, testPkgName, testUid);
587 
588             try {
589                 listener.verify(timeout, testUid, testPkgName, RESTRICTION_LEVEL_ADAPTIVE_BUCKET);
590                 fail("There shouldn't be any level change events");
591             } catch (Exception e) {
592                 // Expected.
593             }
594         }
595 
596         // Toggling restricted bucket.
597         listener.mLatchHolder[0] = new CountDownLatch(1);
598         mIdleStateListener.onAppIdleStateChanged(testPkgName, testUser, false,
599                 STANDBY_BUCKET_RESTRICTED, REASON_MAIN_USAGE);
600         waitForIdleHandler(mBgRestrictionController.getBackgroundHandler());
601         verifyRestrictionLevel(RESTRICTION_LEVEL_RESTRICTED_BUCKET, testPkgName, testUid);
602         listener.verify(timeout, testUid, testPkgName, RESTRICTION_LEVEL_RESTRICTED_BUCKET);
603 
604         // Toggling exempted bucket.
605         listener.mLatchHolder[0] = new CountDownLatch(1);
606         mIdleStateListener.onAppIdleStateChanged(testPkgName, testUser, false,
607                 STANDBY_BUCKET_EXEMPTED, REASON_MAIN_FORCED_BY_SYSTEM);
608         waitForIdleHandler(mBgRestrictionController.getBackgroundHandler());
609         verifyRestrictionLevel(RESTRICTION_LEVEL_EXEMPTED, testPkgName, testUid);
610         listener.verify(timeout, testUid, testPkgName, RESTRICTION_LEVEL_EXEMPTED);
611     }
612 
613     @Test
testBgCurrentDrainMonitor()614     public void testBgCurrentDrainMonitor() throws Exception {
615         final BatteryUsageStats stats = mock(BatteryUsageStats.class);
616         final List<BatteryUsageStats> statsList = Arrays.asList(stats);
617         final int testPkgIndex = 2;
618         final String testPkgName = TEST_PACKAGE_BASE + testPkgIndex;
619         final int testUser = TEST_USER0;
620         final int testUid = UserHandle.getUid(testUser,
621                 TEST_PACKAGE_APPID_BASE + testPkgIndex);
622         final int testUid2 = UserHandle.getUid(testUser,
623                 TEST_PACKAGE_APPID_BASE + testPkgIndex + 1);
624         final TestAppRestrictionLevelListener listener = new TestAppRestrictionLevelListener();
625         final long timeout =
626                 AppBatteryTracker.BATTERY_USAGE_STATS_POLLING_INTERVAL_MS_DEBUG * 2;
627         final long windowMs = 2_000;
628         final float restrictBucketThreshold = 2.0f;
629         final float restrictBucketThresholdMah =
630                 BATTERY_FULL_CHARGE_MAH * restrictBucketThreshold / 100.0f;
631         final float bgRestrictedThreshold = 4.0f;
632         final float bgRestrictedThresholdMah =
633                 BATTERY_FULL_CHARGE_MAH * bgRestrictedThreshold / 100.0f;
634         final int testPid = 1234;
635         final int notificationId = 1000;
636 
637         DeviceConfigSession<Boolean> bgCurrentDrainMonitor = null;
638         DeviceConfigSession<Long> bgCurrentDrainWindow = null;
639         DeviceConfigSession<Long> bgCurrentDrainInteractionGracePeriod = null;
640         DeviceConfigSession<Float> bgCurrentDrainRestrictedBucketThreshold = null;
641         DeviceConfigSession<Float> bgCurrentDrainBgRestrictedThreshold = null;
642         DeviceConfigSession<Boolean> bgCurrentDrainAutoRestrictAbusiveApps = null;
643         DeviceConfigSession<Boolean> bgPromptFgsWithNotiToBgRestricted = null;
644         DeviceConfigSession<Boolean> bgPromptAbusiveAppToBgRestricted = null;
645         DeviceConfigSession<Long> bgNotificationMinInterval = null;
646         DeviceConfigSession<Integer> bgBatteryExemptionTypes = null;
647         DeviceConfigSession<Boolean> bgCurrentDrainDecoupleThresholds = null;
648 
649         mBgRestrictionController.addAppBackgroundRestrictionListener(listener);
650 
651         setBackgroundRestrict(testPkgName, testUid, false, listener);
652 
653         // Verify the current settings.
654         verifyRestrictionLevel(RESTRICTION_LEVEL_ADAPTIVE_BUCKET, testPkgName, testUid);
655 
656         final double[] zeros = new double[]{0.0f, 0.0f};
657         final int[] uids = new int[]{testUid, testUid2};
658 
659         try {
660             bgCurrentDrainMonitor = new DeviceConfigSession<>(
661                     DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
662                     AppBatteryPolicy.KEY_BG_CURRENT_DRAIN_MONITOR_ENABLED,
663                     DeviceConfig::getBoolean,
664                     mContext.getResources().getBoolean(
665                             R.bool.config_bg_current_drain_monitor_enabled));
666             bgCurrentDrainMonitor.set(true);
667 
668             bgCurrentDrainWindow = new DeviceConfigSession<>(
669                     DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
670                     AppBatteryPolicy.KEY_BG_CURRENT_DRAIN_WINDOW,
671                     DeviceConfig::getLong,
672                     (long) mContext.getResources().getInteger(
673                             R.integer.config_bg_current_drain_window));
674             bgCurrentDrainWindow.set(windowMs);
675 
676             bgCurrentDrainInteractionGracePeriod = new DeviceConfigSession<>(
677                     DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
678                     AppBatteryPolicy.KEY_BG_CURRENT_DRAIN_INTERACTION_GRACE_PERIOD,
679                     DeviceConfig::getLong,
680                     (long) mContext.getResources().getInteger(
681                             R.integer.config_bg_current_drain_window));
682             bgCurrentDrainInteractionGracePeriod.set(windowMs);
683 
684             bgCurrentDrainRestrictedBucketThreshold = new DeviceConfigSession<>(
685                     DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
686                     AppBatteryPolicy.KEY_BG_CURRENT_DRAIN_THRESHOLD_TO_RESTRICTED_BUCKET,
687                     DeviceConfig::getFloat,
688                     getFloatArray(mContext.getResources().obtainTypedArray(
689                             R.array.config_bg_current_drain_threshold_to_restricted_bucket))[
690                             isLowRamDeviceStatic() ? 1 : 0]);
691             bgCurrentDrainRestrictedBucketThreshold.set(restrictBucketThreshold);
692 
693             bgCurrentDrainBgRestrictedThreshold = new DeviceConfigSession<>(
694                     DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
695                     AppBatteryPolicy.KEY_BG_CURRENT_DRAIN_THRESHOLD_TO_BG_RESTRICTED,
696                     DeviceConfig::getFloat,
697                     getFloatArray(mContext.getResources().obtainTypedArray(
698                             R.array.config_bg_current_drain_threshold_to_bg_restricted))[
699                             isLowRamDeviceStatic() ? 1 : 0]);
700             bgCurrentDrainBgRestrictedThreshold.set(bgRestrictedThreshold);
701 
702             bgCurrentDrainAutoRestrictAbusiveApps = new DeviceConfigSession<>(
703                     DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
704                     AppBatteryPolicy.KEY_BG_CURRENT_DRAIN_AUTO_RESTRICT_ABUSIVE_APPS_ENABLED,
705                     DeviceConfig::getBoolean,
706                     mContext.getResources().getBoolean(
707                             R.bool.config_bg_current_drain_auto_restrict_abusive_apps));
708             bgCurrentDrainAutoRestrictAbusiveApps.set(true);
709 
710             bgPromptFgsWithNotiToBgRestricted = new DeviceConfigSession<>(
711                     DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
712                     ConstantsObserver.KEY_BG_PROMPT_FGS_WITH_NOTIFICATION_TO_BG_RESTRICTED,
713                     DeviceConfig::getBoolean,
714                     mContext.getResources().getBoolean(
715                             R.bool.config_bg_prompt_fgs_with_noti_to_bg_restricted));
716             bgPromptFgsWithNotiToBgRestricted.set(true);
717 
718             bgPromptAbusiveAppToBgRestricted = new DeviceConfigSession<>(
719                     DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
720                     ConstantsObserver.KEY_BG_PROMPT_ABUSIVE_APPS_TO_BG_RESTRICTED,
721                     DeviceConfig::getBoolean,
722                     mContext.getResources().getBoolean(
723                             R.bool.config_bg_prompt_abusive_apps_to_bg_restricted));
724             bgPromptAbusiveAppToBgRestricted.set(true);
725 
726             bgNotificationMinInterval = new DeviceConfigSession<>(
727                     DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
728                     ConstantsObserver.KEY_BG_ABUSIVE_NOTIFICATION_MINIMAL_INTERVAL,
729                     DeviceConfig::getLong,
730                     ConstantsObserver.DEFAULT_BG_ABUSIVE_NOTIFICATION_MINIMAL_INTERVAL_MS);
731             bgNotificationMinInterval.set(windowMs);
732 
733             bgBatteryExemptionTypes = new DeviceConfigSession<>(
734                     DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
735                     AppBatteryPolicy.KEY_BG_CURRENT_DRAIN_EXEMPTED_TYPES,
736                     DeviceConfig::getInt,
737                     mContext.getResources().getInteger(
738                             R.integer.config_bg_current_drain_exempted_types));
739             bgBatteryExemptionTypes.set(0);
740 
741             bgCurrentDrainDecoupleThresholds = new DeviceConfigSession<>(
742                     DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
743                     AppBatteryPolicy.KEY_BG_CURRENT_DRAIN_DECOUPLE_THRESHOLDS,
744                     DeviceConfig::getBoolean,
745                     AppBatteryPolicy.DEFAULT_BG_CURRENT_DRAIN_DECOUPLE_THRESHOLD);
746             bgCurrentDrainDecoupleThresholds.set(true);
747 
748             mCurrentTimeMillis = 10_000L;
749             doReturn(mCurrentTimeMillis - windowMs).when(stats).getStatsStartTimestamp();
750             doReturn(mCurrentTimeMillis).when(stats).getStatsEndTimestamp();
751             doReturn(statsList).when(mBatteryStatsInternal).getBatteryUsageStats(anyObject());
752             mAppFGSTracker.onForegroundServiceStateChanged(testPkgName, testUid,
753                     testPid, true);
754             mAppFGSTracker.onForegroundServiceNotificationUpdated(
755                     testPkgName, testUid, notificationId, false);
756             mAppFGSTracker.mNotificationListener.onNotificationPosted(new StatusBarNotification(
757                     testPkgName, null, notificationId, null, testUid, testPid,
758                     new Notification(), UserHandle.of(testUser), null, mCurrentTimeMillis), null);
759 
760             runTestBgCurrentDrainMonitorOnce(listener, stats, uids,
761                     new double[]{restrictBucketThresholdMah - 1, 0},
762                     new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
763                     () -> {
764                         doReturn(mCurrentTimeMillis).when(stats).getStatsStartTimestamp();
765                         doReturn(mCurrentTimeMillis + windowMs)
766                                 .when(stats).getStatsEndTimestamp();
767                         mCurrentTimeMillis += windowMs + 1;
768                         try {
769                             listener.verify(timeout, testUid, testPkgName,
770                                     RESTRICTION_LEVEL_ADAPTIVE_BUCKET);
771                             fail("There shouldn't be any level change events");
772                         } catch (Exception e) {
773                             // Expected.
774                         }
775                     });
776 
777             runTestBgCurrentDrainMonitorOnce(listener, stats, uids,
778                     new double[]{restrictBucketThresholdMah + 1, 0},
779                     new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
780                     () -> {
781                         doReturn(mCurrentTimeMillis).when(stats).getStatsStartTimestamp();
782                         doReturn(mCurrentTimeMillis + windowMs)
783                                 .when(stats).getStatsEndTimestamp();
784                         mCurrentTimeMillis += windowMs + 1;
785                         // It should have gone to the restricted bucket.
786                         listener.verify(timeout, testUid, testPkgName,
787                                 RESTRICTION_LEVEL_RESTRICTED_BUCKET);
788                         verify(mInjector.getAppStandbyInternal()).restrictApp(
789                                 eq(testPkgName),
790                                 eq(testUser),
791                                 anyInt(), anyInt());
792                     });
793 
794 
795             runTestBgCurrentDrainMonitorOnce(listener, stats, uids,
796                     new double[]{restrictBucketThresholdMah - 1, 0},
797                     new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
798                     () -> {
799                         doReturn(mCurrentTimeMillis).when(stats).getStatsStartTimestamp();
800                         doReturn(mCurrentTimeMillis + windowMs)
801                                 .when(stats).getStatsEndTimestamp();
802                         mCurrentTimeMillis += windowMs + 1;
803                         // We won't change restriction level until user interactions.
804                         try {
805                             listener.verify(timeout, testUid, testPkgName,
806                                     RESTRICTION_LEVEL_ADAPTIVE_BUCKET);
807                             fail("There shouldn't be any level change events");
808                         } catch (Exception e) {
809                             // Expected.
810                         }
811                         verify(mInjector.getAppStandbyInternal(), never()).setAppStandbyBucket(
812                                 eq(testPkgName),
813                                 eq(STANDBY_BUCKET_RARE),
814                                 eq(testUser),
815                                 anyInt(), anyInt());
816                     });
817 
818             // Trigger user interaction.
819             runTestBgCurrentDrainMonitorOnce(listener, stats, uids,
820                     new double[]{restrictBucketThresholdMah - 1, 0},
821                     new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
822                     () -> {
823                         doReturn(mCurrentTimeMillis).when(stats).getStatsStartTimestamp();
824                         doReturn(mCurrentTimeMillis + windowMs)
825                                 .when(stats).getStatsEndTimestamp();
826                         mCurrentTimeMillis += windowMs + 1;
827                         mIdleStateListener.onUserInteractionStarted(testPkgName, testUser);
828                         waitForIdleHandler(mBgRestrictionController.getBackgroundHandler());
829                         // It should have been back to normal.
830                         listener.verify(timeout, testUid, testPkgName,
831                                 RESTRICTION_LEVEL_ADAPTIVE_BUCKET);
832                         verify(mInjector.getAppStandbyInternal(), atLeast(1)).maybeUnrestrictApp(
833                                 eq(testPkgName),
834                                 eq(testUser),
835                                 eq(REASON_MAIN_FORCED_BY_SYSTEM),
836                                 eq(REASON_SUB_FORCED_SYSTEM_FLAG_ABUSE),
837                                 eq(REASON_MAIN_USAGE),
838                                 eq(REASON_SUB_USAGE_USER_INTERACTION));
839                     });
840 
841             clearInvocations(mInjector.getAppStandbyInternal());
842 
843             // It won't be restricted since user just interacted with it.
844             runTestBgCurrentDrainMonitorOnce(listener, stats, uids,
845                     zeros, new double[]{0, restrictBucketThresholdMah - 1},
846                     zeros, new double[]{restrictBucketThresholdMah + 1, 0},
847                     () -> {
848                         doReturn(mCurrentTimeMillis).when(stats).getStatsStartTimestamp();
849                         doReturn(mCurrentTimeMillis + windowMs)
850                                 .when(stats).getStatsEndTimestamp();
851                         mCurrentTimeMillis += windowMs + 1;
852                         try {
853                             listener.verify(timeout, testUid, testPkgName,
854                                     RESTRICTION_LEVEL_RESTRICTED_BUCKET);
855                             fail("There shouldn't be any level change events");
856                         } catch (Exception e) {
857                             // Expected.
858                         }
859                         verify(mInjector.getAppStandbyInternal(), never()).restrictApp(
860                                 eq(testPkgName),
861                                 eq(testUser),
862                                 anyInt(), anyInt());
863                     });
864 
865             // Sleep a while.
866             Thread.sleep(windowMs);
867             clearInvocations(mInjector.getAppStandbyInternal());
868             // Now it should have been restricted.
869             runTestBgCurrentDrainMonitorOnce(listener, stats, uids,
870                     zeros, new double[]{0, restrictBucketThresholdMah - 1},
871                     zeros, new double[]{restrictBucketThresholdMah + 1, 0},
872                     () -> {
873                         doReturn(mCurrentTimeMillis).when(stats).getStatsStartTimestamp();
874                         doReturn(mCurrentTimeMillis + windowMs)
875                                 .when(stats).getStatsEndTimestamp();
876                         mCurrentTimeMillis += windowMs + 1;
877                         // It should have gone to the restricted bucket.
878                         listener.verify(timeout, testUid, testPkgName,
879                                 RESTRICTION_LEVEL_RESTRICTED_BUCKET);
880                         verify(mInjector.getAppStandbyInternal(), times(1)).restrictApp(
881                                 eq(testPkgName),
882                                 eq(testUser),
883                                 anyInt(), anyInt());
884                     });
885 
886             clearInvocations(mInjector.getAppStandbyInternal());
887             // Drain a bit more, there shouldn't be any level changes.
888             runTestBgCurrentDrainMonitorOnce(listener, stats, uids,
889                     zeros, new double[]{0, restrictBucketThresholdMah - 1},
890                     zeros, new double[]{restrictBucketThresholdMah + 2, 0},
891                     () -> {
892                         doReturn(mCurrentTimeMillis).when(stats).getStatsStartTimestamp();
893                         doReturn(mCurrentTimeMillis + windowMs)
894                                 .when(stats).getStatsEndTimestamp();
895                         mCurrentTimeMillis += windowMs + 1;
896                         // We won't change restriction level until user interactions.
897                         try {
898                             listener.verify(timeout, testUid, testPkgName,
899                                     RESTRICTION_LEVEL_ADAPTIVE_BUCKET);
900                             fail("There shouldn't be any level change events");
901                         } catch (Exception e) {
902                             // Expected.
903                         }
904                         verify(mInjector.getAppStandbyInternal(), never()).setAppStandbyBucket(
905                                 eq(testPkgName),
906                                 eq(STANDBY_BUCKET_RARE),
907                                 eq(testUser),
908                                 anyInt(), anyInt());
909                     });
910 
911             // Pretend we have the standby buckets set above.
912             doReturn(STANDBY_BUCKET_RESTRICTED)
913                     .when(mAppStandbyInternal)
914                     .getAppStandbyBucket(eq(testPkgName), eq(testUser), anyLong(), anyBoolean());
915 
916             // Sleep a while and set a higher drain
917             Thread.sleep(windowMs);
918             clearInvocations(mInjector.getAppStandbyInternal());
919             clearInvocations(mInjector.getNotificationManager());
920             clearInvocations(mBgRestrictionController);
921 
922             // We're not going to prompt the user if the abusive app has a FGS with notification.
923             bgPromptFgsWithNotiToBgRestricted.set(false);
924 
925             runTestBgCurrentDrainMonitorOnce(listener, stats, uids,
926                     new double[]{bgRestrictedThresholdMah + 1, 0},
927                     new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
928                     () -> {
929                         doReturn(mCurrentTimeMillis).when(stats).getStatsStartTimestamp();
930                         doReturn(mCurrentTimeMillis + windowMs)
931                                 .when(stats).getStatsEndTimestamp();
932                         mCurrentTimeMillis += windowMs + 1;
933                         // We won't change restriction level automatically because it needs
934                         // user consent.
935                         try {
936                             listener.verify(timeout, testUid, testPkgName,
937                                     RESTRICTION_LEVEL_BACKGROUND_RESTRICTED);
938                             fail("There shouldn't be level change event like this");
939                         } catch (Exception e) {
940                             // Expected.
941                         }
942                         verify(mInjector.getAppStandbyInternal(), never()).setAppStandbyBucket(
943                                 eq(testPkgName),
944                                 eq(STANDBY_BUCKET_RARE),
945                                 eq(testUser),
946                                 anyInt(), anyInt());
947                         // We should have requested to goto background restricted level.
948                         verify(mBgRestrictionController, times(1)).handleRequestBgRestricted(
949                                 eq(testPkgName),
950                                 eq(testUid));
951                         // However, we won't have the prompt to user posted because the policy
952                         // is not to show that for FGS with notification.
953                         checkNotificationShown(new String[] {testPkgName}, never(), false);
954                     });
955 
956             // Pretend we have the notification dismissed.
957             mAppFGSTracker.onForegroundServiceNotificationUpdated(
958                     testPkgName, testUid, notificationId, true);
959             clearInvocations(mInjector.getAppStandbyInternal());
960             clearInvocations(mInjector.getNotificationManager());
961             clearInvocations(mBgRestrictionController);
962 
963             runTestBgCurrentDrainMonitorOnce(listener, stats, uids,
964                     new double[]{bgRestrictedThresholdMah + 1, 0},
965                     new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
966                     () -> {
967                         doReturn(mCurrentTimeMillis).when(stats).getStatsStartTimestamp();
968                         doReturn(mCurrentTimeMillis + windowMs)
969                                 .when(stats).getStatsEndTimestamp();
970                         mCurrentTimeMillis += windowMs + 1;
971                         // We won't change restriction level automatically because it needs
972                         // user consent.
973                         try {
974                             listener.verify(timeout, testUid, testPkgName,
975                                     RESTRICTION_LEVEL_BACKGROUND_RESTRICTED);
976                             fail("There shouldn't be level change event like this");
977                         } catch (Exception e) {
978                             // Expected.
979                         }
980                         verify(mInjector.getAppStandbyInternal(), never()).setAppStandbyBucket(
981                                 eq(testPkgName),
982                                 eq(STANDBY_BUCKET_RARE),
983                                 eq(testUser),
984                                 anyInt(), anyInt());
985                         // We should have requested to goto background restricted level.
986                         verify(mBgRestrictionController, times(1)).handleRequestBgRestricted(
987                                 eq(testPkgName),
988                                 eq(testUid));
989                         // Verify we have the notification posted now because its FGS is invisible.
990                         checkNotificationShown(new String[] {testPkgName}, atLeast(1), true);
991                     });
992 
993             // Pretend notification is back on.
994             mAppFGSTracker.onForegroundServiceNotificationUpdated(
995                     testPkgName, testUid, notificationId, false);
996             // Now we'll prompt the user even it has a FGS with notification.
997             bgPromptFgsWithNotiToBgRestricted.set(true);
998             clearInvocations(mInjector.getAppStandbyInternal());
999             clearInvocations(mInjector.getNotificationManager());
1000             clearInvocations(mBgRestrictionController);
1001 
1002             runTestBgCurrentDrainMonitorOnce(listener, stats, uids,
1003                     new double[]{bgRestrictedThresholdMah + 1, 0},
1004                     new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
1005                     () -> {
1006                         doReturn(mCurrentTimeMillis).when(stats).getStatsStartTimestamp();
1007                         doReturn(mCurrentTimeMillis + windowMs)
1008                                 .when(stats).getStatsEndTimestamp();
1009                         mCurrentTimeMillis += windowMs + 1;
1010                         // We won't change restriction level automatically because it needs
1011                         // user consent.
1012                         try {
1013                             listener.verify(timeout, testUid, testPkgName,
1014                                     RESTRICTION_LEVEL_BACKGROUND_RESTRICTED);
1015                             fail("There shouldn't be level change event like this");
1016                         } catch (Exception e) {
1017                             // Expected.
1018                         }
1019                         verify(mInjector.getAppStandbyInternal(), never()).setAppStandbyBucket(
1020                                 eq(testPkgName),
1021                                 eq(STANDBY_BUCKET_RARE),
1022                                 eq(testUser),
1023                                 anyInt(), anyInt());
1024                         // We should have requested to goto background restricted level.
1025                         verify(mBgRestrictionController, times(1)).handleRequestBgRestricted(
1026                                 eq(testPkgName),
1027                                 eq(testUid));
1028                         // Verify we have the notification posted.
1029                         checkNotificationShown(new String[] {testPkgName}, atLeast(1), true);
1030                     });
1031 
1032             // Turn ON the FAS for real.
1033             setBackgroundRestrict(testPkgName, testUid, true, listener);
1034 
1035             // Verify it's background restricted now.
1036             verifyRestrictionLevel(RESTRICTION_LEVEL_BACKGROUND_RESTRICTED, testPkgName, testUid);
1037             listener.verify(timeout, testUid, testPkgName, RESTRICTION_LEVEL_BACKGROUND_RESTRICTED);
1038 
1039             // Trigger user interaction.
1040             mIdleStateListener.onUserInteractionStarted(testPkgName, testUser);
1041             waitForIdleHandler(mBgRestrictionController.getBackgroundHandler());
1042 
1043             listener.mLatchHolder[0] = new CountDownLatch(1);
1044             try {
1045                 listener.verify(timeout, testUid, testPkgName,
1046                         RESTRICTION_LEVEL_ADAPTIVE_BUCKET);
1047                 fail("There shouldn't be level change event like this");
1048             } catch (Exception e) {
1049                 // Expected.
1050             }
1051 
1052             // Reset the standby bucket.
1053             doReturn(STANDBY_BUCKET_RARE)
1054                     .when(mAppStandbyInternal)
1055                     .getAppStandbyBucket(eq(testPkgName), eq(testUser), anyLong(), anyBoolean());
1056 
1057             // Turn OFF the FAS.
1058             listener.mLatchHolder[0] = new CountDownLatch(1);
1059             clearInvocations(mInjector.getAppStandbyInternal());
1060             clearInvocations(mBgRestrictionController);
1061             setBackgroundRestrict(testPkgName, testUid, false, listener);
1062 
1063             // It'll go back to restricted bucket because it used to behave poorly.
1064             listener.verify(timeout, testUid, testPkgName, RESTRICTION_LEVEL_RESTRICTED_BUCKET);
1065             verifyRestrictionLevel(RESTRICTION_LEVEL_RESTRICTED_BUCKET, testPkgName, testUid);
1066 
1067             clearInvocations(mInjector.getAppStandbyInternal());
1068             // Trigger user interaction.
1069             runTestBgCurrentDrainMonitorOnce(listener, stats, uids,
1070                     new double[]{restrictBucketThresholdMah - 1, 0},
1071                     new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
1072                     () -> {
1073                         doReturn(mCurrentTimeMillis).when(stats).getStatsStartTimestamp();
1074                         doReturn(mCurrentTimeMillis + windowMs)
1075                                 .when(stats).getStatsEndTimestamp();
1076                         mCurrentTimeMillis += windowMs + 1;
1077                         mIdleStateListener.onUserInteractionStarted(testPkgName, testUser);
1078                         waitForIdleHandler(mBgRestrictionController.getBackgroundHandler());
1079                         // It should have been back to normal.
1080                         listener.verify(timeout, testUid, testPkgName,
1081                                 RESTRICTION_LEVEL_ADAPTIVE_BUCKET);
1082                         verify(mInjector.getAppStandbyInternal(), atLeast(1)).maybeUnrestrictApp(
1083                                 eq(testPkgName),
1084                                 eq(testUser),
1085                                 eq(REASON_MAIN_USAGE),
1086                                 eq(REASON_SUB_USAGE_USER_INTERACTION),
1087                                 eq(REASON_MAIN_USAGE),
1088                                 eq(REASON_SUB_USAGE_USER_INTERACTION));
1089                     });
1090 
1091             bgCurrentDrainDecoupleThresholds.set(true);
1092             clearInvocations(mInjector.getAppStandbyInternal());
1093 
1094             // Go to the threshold right away.
1095             runTestBgCurrentDrainMonitorOnce(listener, stats, uids,
1096                     new double[]{0, restrictBucketThresholdMah - 1},
1097                     new double[]{bgRestrictedThresholdMah + 1, 0}, zeros, zeros,
1098                     () -> {
1099                         doReturn(mCurrentTimeMillis).when(stats).getStatsStartTimestamp();
1100                         doReturn(mCurrentTimeMillis + windowMs)
1101                                 .when(stats).getStatsEndTimestamp();
1102                         mCurrentTimeMillis += windowMs + 1;
1103                         // We won't change restriction level automatically because it needs
1104                         // user consent.
1105                         try {
1106                             listener.verify(timeout, testUid, testPkgName,
1107                                     RESTRICTION_LEVEL_BACKGROUND_RESTRICTED);
1108                             fail("There shouldn't be level change event like this");
1109                         } catch (Exception e) {
1110                             // Expected.
1111                         }
1112                         verify(mInjector.getAppStandbyInternal(), never()).setAppStandbyBucket(
1113                                 eq(testPkgName),
1114                                 eq(STANDBY_BUCKET_RARE),
1115                                 eq(testUser),
1116                                 anyInt(), anyInt());
1117                         // We should have requested to goto background restricted level.
1118                         verify(mBgRestrictionController, times(1)).handleRequestBgRestricted(
1119                                 eq(testPkgName),
1120                                 eq(testUid));
1121                         // Verify we have the notification posted now because its FGS is invisible.
1122                         checkNotificationShown(new String[] {testPkgName}, atLeast(1), true);
1123                     });
1124 
1125             bgCurrentDrainDecoupleThresholds.set(false);
1126             clearInvocations(mInjector.getAppStandbyInternal());
1127             clearInvocations(mBgRestrictionController);
1128 
1129             // Go to the threshold right away, but this time, it shouldn't even request to goto
1130             // bg restricted level because it requires to be in restricted bucket before that.
1131             runTestBgCurrentDrainMonitorOnce(listener, stats, uids,
1132                     new double[]{0, restrictBucketThresholdMah - 1},
1133                     new double[]{bgRestrictedThresholdMah + 1, 0}, zeros, zeros,
1134                     () -> {
1135                         doReturn(mCurrentTimeMillis).when(stats).getStatsStartTimestamp();
1136                         doReturn(mCurrentTimeMillis + windowMs)
1137                                 .when(stats).getStatsEndTimestamp();
1138                         mCurrentTimeMillis += windowMs + 1;
1139                         // We won't change restriction level automatically because it needs
1140                         // user consent.
1141                         try {
1142                             listener.verify(timeout, testUid, testPkgName,
1143                                     RESTRICTION_LEVEL_BACKGROUND_RESTRICTED);
1144                             fail("There shouldn't be level change event like this");
1145                         } catch (Exception e) {
1146                             // Expected.
1147                         }
1148                         verify(mInjector.getAppStandbyInternal(), never()).setAppStandbyBucket(
1149                                 eq(testPkgName),
1150                                 eq(STANDBY_BUCKET_RARE),
1151                                 eq(testUser),
1152                                 anyInt(), anyInt());
1153                         // We should NOT have requested to goto background restricted level.
1154                         verify(mBgRestrictionController, never()).handleRequestBgRestricted(
1155                                 eq(testPkgName),
1156                                 eq(testUid));
1157                     });
1158 
1159         } finally {
1160             closeIfNotNull(bgCurrentDrainMonitor);
1161             closeIfNotNull(bgCurrentDrainWindow);
1162             closeIfNotNull(bgCurrentDrainInteractionGracePeriod);
1163             closeIfNotNull(bgCurrentDrainRestrictedBucketThreshold);
1164             closeIfNotNull(bgCurrentDrainBgRestrictedThreshold);
1165             closeIfNotNull(bgCurrentDrainAutoRestrictAbusiveApps);
1166             closeIfNotNull(bgPromptFgsWithNotiToBgRestricted);
1167             closeIfNotNull(bgPromptAbusiveAppToBgRestricted);
1168             closeIfNotNull(bgNotificationMinInterval);
1169             closeIfNotNull(bgBatteryExemptionTypes);
1170             closeIfNotNull(bgCurrentDrainDecoupleThresholds);
1171         }
1172     }
1173 
1174     @Test
testLongFGSMonitor()1175     public void testLongFGSMonitor() throws Exception {
1176         final int testPkgIndex1 = 1;
1177         final String testPkgName1 = TEST_PACKAGE_BASE + testPkgIndex1;
1178         final int testUser1 = TEST_USER0;
1179         final int testUid1 = UserHandle.getUid(testUser1, TEST_PACKAGE_APPID_BASE + testPkgIndex1);
1180         final int testPid1 = 1234;
1181 
1182         final int testPkgIndex2 = 2;
1183         final String testPkgName2 = TEST_PACKAGE_BASE + testPkgIndex2;
1184         final int testUser2 = TEST_USER0;
1185         final int testUid2 = UserHandle.getUid(testUser2, TEST_PACKAGE_APPID_BASE + testPkgIndex2);
1186         final int testPid2 = 1235;
1187 
1188         final int fgsNotificationId = 1000;
1189 
1190         final long windowMs = 2_000;
1191         final long thresholdMs = 1_000;
1192         final long shortMs = 100;
1193 
1194         DeviceConfigSession<Boolean> longRunningFGSMonitor = null;
1195         DeviceConfigSession<Long> longRunningFGSWindow = null;
1196         DeviceConfigSession<Long> longRunningFGSThreshold = null;
1197         DeviceConfigSession<Boolean> longRunningFGSWithNotification = null;
1198         DeviceConfigSession<Boolean> longRunningFGS = null;
1199 
1200         try {
1201             longRunningFGSMonitor = new DeviceConfigSession<>(
1202                     DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
1203                     AppFGSPolicy.KEY_BG_FGS_MONITOR_ENABLED,
1204                     DeviceConfig::getBoolean,
1205                     AppFGSPolicy.DEFAULT_BG_FGS_MONITOR_ENABLED);
1206             longRunningFGSMonitor.set(true);
1207 
1208             longRunningFGSWindow = new DeviceConfigSession<>(
1209                     DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
1210                     AppFGSPolicy.KEY_BG_FGS_LONG_RUNNING_WINDOW,
1211                     DeviceConfig::getLong,
1212                     AppFGSPolicy.DEFAULT_BG_FGS_LONG_RUNNING_WINDOW);
1213             longRunningFGSWindow.set(windowMs);
1214 
1215             longRunningFGSThreshold = new DeviceConfigSession<>(
1216                     DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
1217                     AppFGSPolicy.KEY_BG_FGS_LONG_RUNNING_THRESHOLD,
1218                     DeviceConfig::getLong,
1219                     AppFGSPolicy.DEFAULT_BG_FGS_LONG_RUNNING_THRESHOLD);
1220             longRunningFGSThreshold.set(thresholdMs);
1221 
1222             longRunningFGSWithNotification = new DeviceConfigSession<>(
1223                     DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
1224                     ConstantsObserver.KEY_BG_PROMPT_FGS_WITH_NOTIFICATION_ON_LONG_RUNNING,
1225                     DeviceConfig::getBoolean,
1226                     ConstantsObserver.DEFAULT_BG_PROMPT_FGS_WITH_NOTIFICATION_ON_LONG_RUNNING);
1227             longRunningFGSWithNotification.set(true);
1228 
1229             longRunningFGS = new DeviceConfigSession<>(
1230                     DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
1231                     ConstantsObserver.KEY_BG_PROMPT_FGS_ON_LONG_RUNNING,
1232                     DeviceConfig::getBoolean,
1233                     ConstantsObserver.DEFAULT_BG_PROMPT_FGS_ON_LONG_RUNNING);
1234             longRunningFGS.set(true);
1235 
1236             // Basic case
1237             mAppFGSTracker.onForegroundServiceStateChanged(testPkgName1, testUid1,
1238                     testPid1, true);
1239             // Verify we have the notification, it'll include the summary notification though.
1240             int notificationId = checkNotificationShown(
1241                     new String[] {testPkgName1}, timeout(windowMs * 2).times(2), true)[0];
1242 
1243             clearInvocations(mInjector.getNotificationManager());
1244             // Sleep a while, verify it won't show another notification.
1245             Thread.sleep(windowMs * 2);
1246             checkNotificationShown(
1247                     new String[] {testPkgName1}, timeout(windowMs * 2).times(0), false);
1248 
1249             // Stop this FGS
1250             mAppFGSTracker.onForegroundServiceStateChanged(testPkgName1, testUid1,
1251                     testPid1, false);
1252             checkNotificationGone(testPkgName1, timeout(windowMs), notificationId);
1253 
1254             clearInvocations(mInjector.getNotificationManager());
1255             // Start another one and stop it.
1256             mAppFGSTracker.onForegroundServiceStateChanged(testPkgName2, testUid2,
1257                     testPid2, true);
1258             Thread.sleep(shortMs);
1259             mAppFGSTracker.onForegroundServiceStateChanged(testPkgName2, testUid2,
1260                     testPid2, false);
1261 
1262             // Not long enough, it shouldn't show notification in this case.
1263             checkNotificationShown(
1264                     new String[] {testPkgName2}, timeout(windowMs * 2).times(0), false);
1265 
1266             clearInvocations(mInjector.getNotificationManager());
1267             // Start the FGS again.
1268             mAppFGSTracker.onForegroundServiceStateChanged(testPkgName2, testUid2,
1269                     testPid2, true);
1270             // Verify we have the notification.
1271             notificationId = checkNotificationShown(
1272                     new String[] {testPkgName2}, timeout(windowMs * 2).times(2), true)[0];
1273 
1274             // Stop this FGS
1275             mAppFGSTracker.onForegroundServiceStateChanged(testPkgName2, testUid2,
1276                     testPid2, false);
1277             checkNotificationGone(testPkgName2, timeout(windowMs), notificationId);
1278 
1279             // Turn OFF the notification.
1280             longRunningFGS.set(false);
1281             clearInvocations(mInjector.getNotificationManager());
1282             mBgRestrictionController.resetRestrictionSettings();
1283             // Start the FGS again.
1284             mAppFGSTracker.onForegroundServiceStateChanged(testPkgName2, testUid2,
1285                     testPid2, true);
1286             // Verify we do NOT have the notification.
1287             checkNotificationShown(
1288                     new String[] {testPkgName2}, timeout(windowMs * 2).times(0), false);
1289             // Stop this FGS
1290             mAppFGSTracker.onForegroundServiceStateChanged(testPkgName2, testUid2,
1291                     testPid2, false);
1292 
1293             // Turn it back ON.
1294             longRunningFGS.set(true);
1295 
1296             // Start over with concurrent cases.
1297             clearInvocations(mInjector.getNotificationManager());
1298             mBgRestrictionController.resetRestrictionSettings();
1299             mAppFGSTracker.onForegroundServiceStateChanged(testPkgName2, testUid2,
1300                     testPid2, true);
1301             Thread.sleep(shortMs);
1302             mAppFGSTracker.onForegroundServiceStateChanged(testPkgName1, testUid1,
1303                     testPid1, true);
1304 
1305             // Verify we've seen both notifications, and test pkg2 should be shown before test pkg1.
1306             int[] notificationIds = checkNotificationShown(
1307                     new String[] {testPkgName2, testPkgName1},
1308                     timeout(windowMs * 2).times(4), true);
1309 
1310             // Stop both of them.
1311             mAppFGSTracker.onForegroundServiceStateChanged(testPkgName1, testUid1,
1312                     testPid1, false);
1313             checkNotificationGone(testPkgName1, timeout(windowMs), notificationIds[1]);
1314             clearInvocations(mInjector.getNotificationManager());
1315             mAppFGSTracker.onForegroundServiceStateChanged(testPkgName2, testUid2,
1316                     testPid2, false);
1317             checkNotificationGone(testPkgName2, timeout(windowMs), notificationIds[0]);
1318 
1319             // Test the interlaced case.
1320             clearInvocations(mInjector.getNotificationManager());
1321             mBgRestrictionController.resetRestrictionSettings();
1322             mAppFGSTracker.reset();
1323             mAppFGSTracker.onForegroundServiceStateChanged(testPkgName1, testUid1,
1324                     testPid1, true);
1325 
1326             final long initialWaitMs = thresholdMs / 2;
1327             Thread.sleep(initialWaitMs);
1328 
1329             for (long remaining = thresholdMs - initialWaitMs; remaining > 0;) {
1330                 mAppFGSTracker.onForegroundServiceStateChanged(testPkgName1, testUid1,
1331                         testPid1, false);
1332                 mAppFGSTracker.onForegroundServiceStateChanged(testPkgName2, testUid2,
1333                         testPid2, true);
1334                 Thread.sleep(shortMs);
1335                 mAppFGSTracker.onForegroundServiceStateChanged(testPkgName1, testUid1,
1336                         testPid1, true);
1337                 mAppFGSTracker.onForegroundServiceStateChanged(testPkgName2, testUid2,
1338                         testPid2, false);
1339                 Thread.sleep(shortMs);
1340                 remaining -= shortMs;
1341             }
1342 
1343             // Verify test pkg1 got the notification, but not test pkg2.
1344             notificationId = checkNotificationShown(
1345                     new String[] {testPkgName1}, timeout(windowMs).times(2), true)[0];
1346 
1347             clearInvocations(mInjector.getNotificationManager());
1348             // Stop the FGS.
1349             mAppFGSTracker.onForegroundServiceStateChanged(testPkgName1, testUid1,
1350                     testPid1, false);
1351             checkNotificationGone(testPkgName1, timeout(windowMs), notificationId);
1352 
1353             // Start over with the flag to not show prompt when it has an active notification.
1354             clearInvocations(mInjector.getNotificationManager());
1355             mBgRestrictionController.resetRestrictionSettings();
1356             longRunningFGSWithNotification.set(false);
1357 
1358             // Start an FGS with notification.
1359             mAppFGSTracker.onForegroundServiceStateChanged(testPkgName1, testUid1,
1360                     testPid1, true);
1361             mAppFGSTracker.onForegroundServiceNotificationUpdated(
1362                     testPkgName1, testUid1, fgsNotificationId, false);
1363             mAppFGSTracker.mNotificationListener.onNotificationPosted(new StatusBarNotification(
1364                     testPkgName1, null, fgsNotificationId, null, testUid1, testPid1,
1365                     new Notification(), UserHandle.of(testUser1), null, mCurrentTimeMillis), null);
1366 
1367             // Verify we won't prompt the user because it has a visible FGS notification.
1368             checkNotificationShown(
1369                     new String[] {testPkgName1}, timeout(windowMs * 2).times(0), false);
1370 
1371             // Pretend we have the notification dismissed.
1372             mAppFGSTracker.onForegroundServiceNotificationUpdated(
1373                     testPkgName1, testUid1, fgsNotificationId, true);
1374 
1375             // Verify we have the notification.
1376             notificationId = checkNotificationShown(
1377                     new String[] {testPkgName1}, timeout(windowMs * 2).times(2), true)[0];
1378 
1379             // Stop the FGS.
1380             mAppFGSTracker.onForegroundServiceStateChanged(testPkgName1, testUid1,
1381                     testPid1, false);
1382             checkNotificationGone(testPkgName1, timeout(windowMs), notificationId);
1383         } finally {
1384             closeIfNotNull(longRunningFGSMonitor);
1385             closeIfNotNull(longRunningFGSWindow);
1386             closeIfNotNull(longRunningFGSThreshold);
1387             closeIfNotNull(longRunningFGSWithNotification);
1388             closeIfNotNull(longRunningFGS);
1389         }
1390     }
1391 
1392     @Test
testLongFGSExemptions()1393     public void testLongFGSExemptions() throws Exception {
1394         final int testPkgIndex1 = 1;
1395         final String testPkgName1 = TEST_PACKAGE_BASE + testPkgIndex1;
1396         final int testUser1 = TEST_USER0;
1397         final int testUid1 = UserHandle.getUid(testUser1, TEST_PACKAGE_APPID_BASE + testPkgIndex1);
1398         final int testPid1 = 1234;
1399 
1400         final int testPkgIndex2 = 2;
1401         final String testPkgName2 = TEST_PACKAGE_BASE + testPkgIndex2;
1402         final int testUser2 = TEST_USER0;
1403         final int testUid2 = UserHandle.getUid(testUser2, TEST_PACKAGE_APPID_BASE + testPkgIndex2);
1404         final int testPid2 = 1235;
1405 
1406         final long windowMs = 2_000;
1407         final long thresholdMs = 1_000;
1408 
1409         DeviceConfigSession<Boolean> longRunningFGSMonitor = null;
1410         DeviceConfigSession<Long> longRunningFGSWindow = null;
1411         DeviceConfigSession<Long> longRunningFGSThreshold = null;
1412         DeviceConfigSession<Long> mediaPlaybackFGSThreshold = null;
1413         DeviceConfigSession<Long> locationFGSThreshold = null;
1414         DeviceConfigSession<Boolean> longRunningFGSWithNotification = null;
1415         DeviceConfigSession<Boolean> longRunningFGS = null;
1416 
1417         doReturn(testPkgName1).when(mInjector).getPackageName(testPid1);
1418         doReturn(testPkgName2).when(mInjector).getPackageName(testPid2);
1419 
1420         try {
1421             longRunningFGSMonitor = new DeviceConfigSession<>(
1422                     DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
1423                     AppFGSPolicy.KEY_BG_FGS_MONITOR_ENABLED,
1424                     DeviceConfig::getBoolean,
1425                     AppFGSPolicy.DEFAULT_BG_FGS_MONITOR_ENABLED);
1426             longRunningFGSMonitor.set(true);
1427 
1428             longRunningFGSWindow = new DeviceConfigSession<>(
1429                     DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
1430                     AppFGSPolicy.KEY_BG_FGS_LONG_RUNNING_WINDOW,
1431                     DeviceConfig::getLong,
1432                     AppFGSPolicy.DEFAULT_BG_FGS_LONG_RUNNING_WINDOW);
1433             longRunningFGSWindow.set(windowMs);
1434 
1435             longRunningFGSThreshold = new DeviceConfigSession<>(
1436                     DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
1437                     AppFGSPolicy.KEY_BG_FGS_LONG_RUNNING_THRESHOLD,
1438                     DeviceConfig::getLong,
1439                     AppFGSPolicy.DEFAULT_BG_FGS_LONG_RUNNING_THRESHOLD);
1440             longRunningFGSThreshold.set(thresholdMs);
1441 
1442             mediaPlaybackFGSThreshold = new DeviceConfigSession<>(
1443                     DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
1444                     AppFGSPolicy.KEY_BG_FGS_MEDIA_PLAYBACK_THRESHOLD,
1445                     DeviceConfig::getLong,
1446                     AppFGSPolicy.DEFAULT_BG_FGS_MEDIA_PLAYBACK_THRESHOLD);
1447             mediaPlaybackFGSThreshold.set(thresholdMs);
1448 
1449             locationFGSThreshold = new DeviceConfigSession<>(
1450                     DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
1451                     AppFGSPolicy.KEY_BG_FGS_LOCATION_THRESHOLD,
1452                     DeviceConfig::getLong,
1453                     AppFGSPolicy.DEFAULT_BG_FGS_LOCATION_THRESHOLD);
1454             locationFGSThreshold.set(thresholdMs);
1455 
1456             longRunningFGSWithNotification = new DeviceConfigSession<>(
1457                     DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
1458                     ConstantsObserver.KEY_BG_PROMPT_FGS_WITH_NOTIFICATION_ON_LONG_RUNNING,
1459                     DeviceConfig::getBoolean,
1460                     ConstantsObserver.DEFAULT_BG_PROMPT_FGS_WITH_NOTIFICATION_ON_LONG_RUNNING);
1461             longRunningFGSWithNotification.set(true);
1462 
1463             longRunningFGS = new DeviceConfigSession<>(
1464                     DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
1465                     ConstantsObserver.KEY_BG_PROMPT_FGS_ON_LONG_RUNNING,
1466                     DeviceConfig::getBoolean,
1467                     ConstantsObserver.DEFAULT_BG_PROMPT_FGS_ON_LONG_RUNNING);
1468             longRunningFGS.set(true);
1469 
1470             // Long-running FGS with type "location", but ran for a very short time.
1471             runTestLongFGSExemptionOnce(testPkgName1, testUid1, testPid1,
1472                     FOREGROUND_SERVICE_TYPE_LOCATION, 0, null, OP_NONE, null, null,
1473                     timeout(windowMs * 2).times(2));
1474 
1475             // Long-running FGS with type "location", and ran for a while.
1476             // We shouldn't see notifications in this case.
1477             runTestLongFGSExemptionOnce(testPkgName1, testUid1, testPid1,
1478                     FOREGROUND_SERVICE_TYPE_LOCATION, thresholdMs * 2, null, OP_NONE, null, null,
1479                     timeout(windowMs * 2).times(0));
1480 
1481             // Long-running FGS with background location permission.
1482             runTestLongFGSExemptionOnce(testPkgName1, testUid1, testPid1,
1483                     FOREGROUND_SERVICE_TYPE_LOCATION, 0, ACCESS_BACKGROUND_LOCATION, OP_NONE,
1484                     null, null, timeout(windowMs * 2).times(0));
1485 
1486             // Long-running FGS with type "mediaPlayback", but ran for a very short time.
1487             runTestLongFGSExemptionOnce(testPkgName1, testUid1, testPid1,
1488                     FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK, 0, null, OP_NONE, null, null,
1489                     timeout(windowMs * 2).times(2));
1490 
1491             // Long-running FGS with type "mediaPlayback", and ran for a while.
1492             // We shouldn't see notifications in this case.
1493             runTestLongFGSExemptionOnce(testPkgName1, testUid1, testPid1,
1494                     FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK, thresholdMs * 2, null, OP_NONE,
1495                     null, null, timeout(windowMs * 2).times(0));
1496 
1497             // Long-running FGS with type "camera", and ran for a while.
1498             // We shouldn't see notifications in this case.
1499             runTestLongFGSExemptionOnce(testPkgName1, testUid1, testPid1,
1500                     FOREGROUND_SERVICE_TYPE_CAMERA, thresholdMs * 2, null, OP_NONE, null, null,
1501                     timeout(windowMs * 2).times(0));
1502 
1503             // Long-running FGS with type "location|mediaPlayback", but ran for a very short time.
1504             runTestLongFGSExemptionOnce(testPkgName1, testUid1, testPid1,
1505                     FOREGROUND_SERVICE_TYPE_LOCATION | FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK,
1506                     0, null, OP_NONE, null, null, timeout(windowMs * 2).times(2));
1507 
1508             // Long-running FGS with type "location|mediaPlayback", and ran for a while.
1509             // We shouldn't see notifications in this case.
1510             runTestLongFGSExemptionOnce(testPkgName1, testUid1, testPid1,
1511                     FOREGROUND_SERVICE_TYPE_LOCATION | FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK,
1512                     thresholdMs * 2, null, OP_NONE, null, null, timeout(windowMs * 2).times(0));
1513 
1514             // Long-running FGS with a media session starts/stops right away.
1515             runTestLongFGSExemptionOnce(testPkgName1, testUid1, testPid1,
1516                     FOREGROUND_SERVICE_TYPE_NONE, 0, null, OP_NONE,
1517                     List.of(Pair.create(createMediaControllers(
1518                             new String[] {testPkgName1}, new int[] {testUid1}), 0L)), null,
1519                     timeout(windowMs * 2).times(2));
1520 
1521             // Long-running FGS with media session, and ran for a while.
1522             // We shouldn't see notifications in this case.
1523             runTestLongFGSExemptionOnce(testPkgName1, testUid1, testPid1,
1524                     FOREGROUND_SERVICE_TYPE_NONE, thresholdMs * 2, null, OP_NONE,
1525                     List.of(Pair.create(createMediaControllers(new String[] {testPkgName1},
1526                             new int[] {testUid1}), thresholdMs * 2)), null,
1527                     timeout(windowMs * 2).times(0));
1528 
1529             // Long-running FGS with 2 media sessions start/stop right away
1530             runTestLongFGSExemptionOnce(testPkgName1, testUid1, testPid1,
1531                     FOREGROUND_SERVICE_TYPE_NONE, 0, null, OP_NONE,
1532                     List.of(Pair.create(createMediaControllers(
1533                             new String[] {testPkgName1, testPkgName2},
1534                             new int[] {testUid1, testUid2}), 0L)), null,
1535                     timeout(windowMs * 2).times(2));
1536 
1537             // Long-running FGS with 2 media sessions start/stop interlaced.
1538             runTestLongFGSExemptionOnce(testPkgName1, testUid1, testPid1,
1539                     FOREGROUND_SERVICE_TYPE_NONE, 0, null, OP_NONE,
1540                     List.of(Pair.create(createMediaControllers(
1541                                     new String[] {testPkgName1, testPkgName2},
1542                                     new int[] {testUid1, testUid2}), thresholdMs),
1543                             Pair.create(createMediaControllers(
1544                                     new String[] {testPkgName1},
1545                                     new int[] {testUid1}), thresholdMs / 10),
1546                             Pair.create(createMediaControllers(
1547                                     new String[] {testPkgName2},
1548                                     new int[] {testUid2}), thresholdMs / 10),
1549                             Pair.create(createMediaControllers(
1550                                     new String[] {testPkgName1},
1551                                     new int[] {testUid1}), thresholdMs / 10)
1552                             ), null,
1553                     timeout(windowMs * 2).times(0));
1554 
1555             // Long-running FGS with top state for a very short time.
1556             runTestLongFGSExemptionOnce(testPkgName1, testUid1, testPid1,
1557                     FOREGROUND_SERVICE_TYPE_NONE, 0, null, OP_NONE, null, List.of(0L),
1558                     timeout(windowMs * 2).times(2));
1559 
1560             // Long-running FGS with top state for extended time.
1561             runTestLongFGSExemptionOnce(testPkgName1, testUid1, testPid1,
1562                     FOREGROUND_SERVICE_TYPE_NONE, 0, null, OP_NONE, null,
1563                     List.of(0L, windowMs * 2, 0L), timeout(windowMs * 2).times(0));
1564 
1565             // Long-running FGS with top state, on and off frequently.
1566             runTestLongFGSExemptionOnce(testPkgName1, testUid1, testPid1,
1567                     FOREGROUND_SERVICE_TYPE_NONE, 0, null, OP_NONE, null,
1568                     List.of(0L, thresholdMs / 10, thresholdMs / 10, thresholdMs / 10,
1569                             thresholdMs / 10, thresholdMs / 10, thresholdMs / 10),
1570                     timeout(windowMs * 2).times(2));
1571         } finally {
1572             closeIfNotNull(longRunningFGSMonitor);
1573             closeIfNotNull(longRunningFGSWindow);
1574             closeIfNotNull(longRunningFGSThreshold);
1575             closeIfNotNull(mediaPlaybackFGSThreshold);
1576             closeIfNotNull(locationFGSThreshold);
1577             closeIfNotNull(longRunningFGSWithNotification);
1578             closeIfNotNull(longRunningFGS);
1579         }
1580     }
1581 
resetBgRestrictionController()1582     private void resetBgRestrictionController() {
1583         mBgRestrictionController.resetRestrictionSettings();
1584         waitForIdleHandler(mBgRestrictionController.getBackgroundHandler());
1585     }
1586 
runTestLongFGSExemptionOnce(String packageName, int uid, int pid, int serviceType, long sleepMs, String perm, int op, List<Pair<List<MediaController>, Long>> mediaControllers, List<Long> topStateChanges, VerificationMode mode)1587     private void runTestLongFGSExemptionOnce(String packageName, int uid, int pid,
1588             int serviceType, long sleepMs, String perm, int op,
1589             List<Pair<List<MediaController>, Long>> mediaControllers, List<Long> topStateChanges,
1590             VerificationMode mode) throws Exception {
1591         runExemptionTestOnce(
1592                 packageName, uid, pid, serviceType, sleepMs, true, false, perm, op,
1593                 mediaControllers, topStateChanges, true, true,
1594                 () -> checkNotificationShown(new String[] {packageName}, mode, false)
1595         );
1596     }
1597 
runExemptionTestOnce(String packageName, int uid, int pid, int serviceType, long sleepMs, boolean stopAfterSleep, boolean withNotification, String perm, int op, List<Pair<List<MediaController>, Long>> mediaControllers, List<Long> topStateChanges, boolean resetFGSTracker, boolean resetController, RunnableWithException r)1598     private void runExemptionTestOnce(String packageName, int uid, int pid,
1599             int serviceType, long sleepMs, boolean stopAfterSleep,
1600             boolean withNotification, String perm, int op,
1601             List<Pair<List<MediaController>, Long>> mediaControllers,
1602             List<Long> topStateChanges, boolean resetFGSTracker, boolean resetController,
1603             RunnableWithException r) throws Exception {
1604         if (resetFGSTracker) {
1605             mAppFGSTracker.reset();
1606             mAppMediaSessionTracker.reset();
1607         }
1608         if (resetController) {
1609             resetBgRestrictionController();
1610         }
1611         clearInvocations(mInjector.getNotificationManager());
1612 
1613         Thread topStateThread = null;
1614         if (topStateChanges != null) {
1615             final CountDownLatch latch = new CountDownLatch(1);
1616             topStateThread = new Thread(() -> {
1617                 try {
1618                     latch.await();
1619                     boolean top = false;
1620                     for (long l: topStateChanges) {
1621                         mUidObservers.onUidStateChanged(uid,
1622                                 top ? PROCESS_STATE_TOP : PROCESS_STATE_FOREGROUND_SERVICE,
1623                                 0, 0);
1624                         top = !top;
1625                         Thread.sleep(l);
1626                     }
1627                     mUidObservers.onUidGone(uid, false);
1628                 } catch (InterruptedException | RemoteException e) {
1629                 }
1630             });
1631             topStateThread.start();
1632             latch.countDown();
1633         }
1634 
1635         mAppFGSTracker.onForegroundServiceStateChanged(packageName, uid, pid, true);
1636         if (serviceType != FOREGROUND_SERVICE_TYPE_NONE) {
1637             mAppFGSTracker.mProcessObserver.onForegroundServicesChanged(pid, uid, serviceType);
1638             Thread.sleep(sleepMs);
1639             if (stopAfterSleep) {
1640                 // Stop it now.
1641                 mAppFGSTracker.mProcessObserver.onForegroundServicesChanged(pid, uid,
1642                         FOREGROUND_SERVICE_TYPE_NONE);
1643             }
1644         }
1645         if (withNotification) {
1646             final int notificationId = 1000;
1647             mAppFGSTracker.onForegroundServiceNotificationUpdated(
1648                     packageName, uid, notificationId, false);
1649             final StatusBarNotification noti = new StatusBarNotification(
1650                     packageName, null, notificationId, null, uid, pid,
1651                     new Notification(), UserHandle.of(UserHandle.getUserId(uid)),
1652                     null, mCurrentTimeMillis);
1653             mAppFGSTracker.mNotificationListener.onNotificationPosted(noti, null);
1654             Thread.sleep(sleepMs);
1655             if (stopAfterSleep) {
1656                 mAppFGSTracker.mNotificationListener.onNotificationRemoved(noti, null, 0);
1657             }
1658         }
1659         if (perm != null) {
1660             setPermissionState(packageName, uid, perm, true);
1661             if (op != OP_NONE) {
1662                 setAppOpState(packageName, uid, op, true);
1663             }
1664             mInjector.getAppPermissionTracker().onPermissionsChanged(uid);
1665         }
1666 
1667         if (mediaControllers != null) {
1668             for (Pair<List<MediaController>, Long> entry: mediaControllers) {
1669                 mActiveSessionListener.onActiveSessionsChanged(entry.first);
1670                 Thread.sleep(entry.second);
1671             }
1672             if (stopAfterSleep) {
1673                 // Stop it now.
1674                 mActiveSessionListener.onActiveSessionsChanged(null);
1675             }
1676         }
1677 
1678         r.run();
1679 
1680         // Stop this FGS
1681         mAppFGSTracker.onForegroundServiceStateChanged(packageName, uid, pid, false);
1682 
1683         if (perm != null) {
1684             setPermissionState(packageName, uid, perm, false);
1685             if (op != OP_NONE) {
1686                 setAppOpState(packageName, uid, op, false);
1687             }
1688             mInjector.getAppPermissionTracker().onPermissionsChanged(uid);
1689         }
1690         if (topStateThread != null) {
1691             topStateThread.join();
1692         }
1693     }
1694 
createMediaControllers(String[] packageNames, int[] uids)1695     private List<MediaController> createMediaControllers(String[] packageNames, int[] uids) {
1696         final ArrayList<MediaController> controllers = new ArrayList<>();
1697         for (int i = 0; i < packageNames.length; i++) {
1698             controllers.add(createMediaController(packageNames[i], uids[i]));
1699         }
1700         return controllers;
1701     }
1702 
createMediaController(String packageName, int uid)1703     private MediaController createMediaController(String packageName, int uid) {
1704         final MediaController controller = mock(MediaController.class);
1705         final MediaSession.Token token = mock(MediaSession.Token.class);
1706         doReturn(packageName).when(controller).getPackageName();
1707         doReturn(token).when(controller).getSessionToken();
1708         doReturn(uid).when(token).getUid();
1709         return controller;
1710     }
1711 
1712     @Test
testBgCurrentDrainMonitorExemptions()1713     public void testBgCurrentDrainMonitorExemptions() throws Exception {
1714         final BatteryUsageStats stats = mock(BatteryUsageStats.class);
1715         final List<BatteryUsageStats> statsList = Arrays.asList(stats);
1716         final int testPkgIndex1 = 1;
1717         final String testPkgName1 = TEST_PACKAGE_BASE + testPkgIndex1;
1718         final int testUser = TEST_USER0;
1719         final int testUid1 = UserHandle.getUid(testUser,
1720                 TEST_PACKAGE_APPID_BASE + testPkgIndex1);
1721         final int testPid1 = 1234;
1722         final int testPkgIndex2 = 2;
1723         final String testPkgName2 = TEST_PACKAGE_BASE + testPkgIndex2;
1724         final int testUid2 = UserHandle.getUid(testUser,
1725                 TEST_PACKAGE_APPID_BASE + testPkgIndex2);
1726         final int testPid2 = 1235;
1727         final TestAppRestrictionLevelListener listener = new TestAppRestrictionLevelListener();
1728         final long timeout =
1729                 AppBatteryTracker.BATTERY_USAGE_STATS_POLLING_INTERVAL_MS_DEBUG * 2;
1730         final long windowMs = 2_000;
1731         final float restrictBucketThreshold = 2.0f;
1732         final float restrictBucketThresholdMah =
1733                 BATTERY_FULL_CHARGE_MAH * restrictBucketThreshold / 100.0f;
1734         final float bgRestrictedThreshold = 4.0f;
1735         final float bgRestrictedThresholdMah =
1736                 BATTERY_FULL_CHARGE_MAH * bgRestrictedThreshold / 100.0f;
1737         final float restrictBucketHighThreshold = 25.0f;
1738         final float restrictBucketHighThresholdMah =
1739                 BATTERY_FULL_CHARGE_MAH * restrictBucketHighThreshold / 100.0f;
1740         final float bgRestrictedHighThreshold = 25.0f;
1741         final float bgRestrictedHighThresholdMah =
1742                 BATTERY_FULL_CHARGE_MAH * bgRestrictedHighThreshold / 100.0f;
1743         final long bgMediaPlaybackMinDuration = 1_000L;
1744         final long bgLocationMinDuration = 1_000L;
1745 
1746         DeviceConfigSession<Boolean> bgCurrentDrainMonitor = null;
1747         DeviceConfigSession<Long> bgCurrentDrainWindow = null;
1748         DeviceConfigSession<Long> bgCurrentDrainInteractionGracePeriod = null;
1749         DeviceConfigSession<Float> bgCurrentDrainRestrictedBucketThreshold = null;
1750         DeviceConfigSession<Float> bgCurrentDrainBgRestrictedThreshold = null;
1751         DeviceConfigSession<Float> bgCurrentDrainRestrictedBucketHighThreshold = null;
1752         DeviceConfigSession<Float> bgCurrentDrainBgRestrictedHighThreshold = null;
1753         DeviceConfigSession<Boolean> bgCurrentDrainAutoRestrictAbusiveApps = null;
1754         DeviceConfigSession<Long> bgMediaPlaybackMinDurationThreshold = null;
1755         DeviceConfigSession<Long> bgLocationMinDurationThreshold = null;
1756         DeviceConfigSession<Boolean> bgCurrentDrainEventDurationBasedThresholdEnabled = null;
1757         DeviceConfigSession<Boolean> bgBatteryExemptionEnabled = null;
1758         DeviceConfigSession<Integer> bgBatteryExemptionTypes = null;
1759         DeviceConfigSession<Boolean> bgPermissionMonitorEnabled = null;
1760         DeviceConfigSession<String> bgPermissionsInMonitor = null;
1761         DeviceConfigSession<Boolean> bgCurrentDrainHighThresholdByBgLocation = null;
1762         DeviceConfigSession<Boolean> bgCurrentDrainDecoupleThresholds = null;
1763         DeviceConfigSession<Boolean> bgPromptAbusiveAppToBgRestricted = null;
1764 
1765         mBgRestrictionController.addAppBackgroundRestrictionListener(listener);
1766 
1767         setBackgroundRestrict(testPkgName1, testUid1, false, listener);
1768 
1769         // Verify the current settings.
1770         verifyRestrictionLevel(RESTRICTION_LEVEL_ADAPTIVE_BUCKET, testPkgName1, testUid1);
1771 
1772         final double[] zeros = new double[]{0.0f, 0.0f};
1773         final int[] uids = new int[]{testUid1, testUid2};
1774 
1775         doReturn(testPkgName1).when(mInjector).getPackageName(testPid1);
1776         doReturn(testPkgName2).when(mInjector).getPackageName(testPid2);
1777 
1778         try {
1779             bgCurrentDrainMonitor = new DeviceConfigSession<>(
1780                     DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
1781                     AppBatteryPolicy.KEY_BG_CURRENT_DRAIN_MONITOR_ENABLED,
1782                     DeviceConfig::getBoolean,
1783                     mContext.getResources().getBoolean(
1784                             R.bool.config_bg_current_drain_monitor_enabled));
1785             bgCurrentDrainMonitor.set(true);
1786 
1787             bgCurrentDrainWindow = new DeviceConfigSession<>(
1788                     DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
1789                     AppBatteryPolicy.KEY_BG_CURRENT_DRAIN_WINDOW,
1790                     DeviceConfig::getLong,
1791                     (long) mContext.getResources().getInteger(
1792                             R.integer.config_bg_current_drain_window));
1793             bgCurrentDrainWindow.set(windowMs);
1794 
1795             bgCurrentDrainInteractionGracePeriod = new DeviceConfigSession<>(
1796                     DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
1797                     AppBatteryPolicy.KEY_BG_CURRENT_DRAIN_INTERACTION_GRACE_PERIOD,
1798                     DeviceConfig::getLong,
1799                     (long) mContext.getResources().getInteger(
1800                             R.integer.config_bg_current_drain_window));
1801             bgCurrentDrainInteractionGracePeriod.set(windowMs);
1802 
1803             bgCurrentDrainRestrictedBucketThreshold = new DeviceConfigSession<>(
1804                     DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
1805                     AppBatteryPolicy.KEY_BG_CURRENT_DRAIN_THRESHOLD_TO_RESTRICTED_BUCKET,
1806                     DeviceConfig::getFloat,
1807                     getFloatArray(mContext.getResources().obtainTypedArray(
1808                             R.array.config_bg_current_drain_threshold_to_restricted_bucket))[
1809                             isLowRamDeviceStatic() ? 1 : 0]);
1810             bgCurrentDrainRestrictedBucketThreshold.set(restrictBucketThreshold);
1811 
1812             bgCurrentDrainBgRestrictedThreshold = new DeviceConfigSession<>(
1813                     DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
1814                     AppBatteryPolicy.KEY_BG_CURRENT_DRAIN_THRESHOLD_TO_BG_RESTRICTED,
1815                     DeviceConfig::getFloat,
1816                     getFloatArray(mContext.getResources().obtainTypedArray(
1817                             R.array.config_bg_current_drain_threshold_to_bg_restricted))[
1818                             isLowRamDeviceStatic() ? 1 : 0]);
1819             bgCurrentDrainBgRestrictedThreshold.set(bgRestrictedThreshold);
1820 
1821             bgCurrentDrainRestrictedBucketHighThreshold = new DeviceConfigSession<>(
1822                     DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
1823                     AppBatteryPolicy.KEY_BG_CURRENT_DRAIN_HIGH_THRESHOLD_TO_RESTRICTED_BUCKET,
1824                     DeviceConfig::getFloat,
1825                     getFloatArray(mContext.getResources().obtainTypedArray(
1826                             R.array.config_bg_current_drain_high_threshold_to_restricted_bucket))[
1827                             isLowRamDeviceStatic() ? 1 : 0]);
1828             bgCurrentDrainRestrictedBucketHighThreshold.set(restrictBucketHighThreshold);
1829 
1830             bgCurrentDrainBgRestrictedHighThreshold = new DeviceConfigSession<>(
1831                     DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
1832                     AppBatteryPolicy.KEY_BG_CURRENT_DRAIN_HIGH_THRESHOLD_TO_BG_RESTRICTED,
1833                     DeviceConfig::getFloat,
1834                     getFloatArray(mContext.getResources().obtainTypedArray(
1835                             R.array.config_bg_current_drain_high_threshold_to_bg_restricted))[
1836                             isLowRamDeviceStatic() ? 1 : 0]);
1837             bgCurrentDrainBgRestrictedHighThreshold.set(bgRestrictedHighThreshold);
1838 
1839             bgCurrentDrainAutoRestrictAbusiveApps = new DeviceConfigSession<>(
1840                     DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
1841                     AppBatteryPolicy.KEY_BG_CURRENT_DRAIN_AUTO_RESTRICT_ABUSIVE_APPS_ENABLED,
1842                     DeviceConfig::getBoolean,
1843                     mContext.getResources().getBoolean(
1844                             R.bool.config_bg_current_drain_auto_restrict_abusive_apps));
1845             bgCurrentDrainAutoRestrictAbusiveApps.set(true);
1846 
1847             bgMediaPlaybackMinDurationThreshold = new DeviceConfigSession<>(
1848                     DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
1849                     AppBatteryPolicy.KEY_BG_CURRENT_DRAIN_MEDIA_PLAYBACK_MIN_DURATION,
1850                     DeviceConfig::getLong,
1851                     (long) mContext.getResources().getInteger(
1852                             R.integer.config_bg_current_drain_media_playback_min_duration));
1853             bgMediaPlaybackMinDurationThreshold.set(bgMediaPlaybackMinDuration);
1854 
1855             bgLocationMinDurationThreshold = new DeviceConfigSession<>(
1856                     DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
1857                     AppBatteryPolicy.KEY_BG_CURRENT_DRAIN_LOCATION_MIN_DURATION,
1858                     DeviceConfig::getLong,
1859                     (long) mContext.getResources().getInteger(
1860                             R.integer.config_bg_current_drain_location_min_duration));
1861             bgLocationMinDurationThreshold.set(bgLocationMinDuration);
1862 
1863             bgCurrentDrainEventDurationBasedThresholdEnabled = new DeviceConfigSession<>(
1864                     DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
1865                     AppBatteryPolicy.KEY_BG_CURRENT_DRAIN_EVENT_DURATION_BASED_THRESHOLD_ENABLED,
1866                     DeviceConfig::getBoolean,
1867                     mContext.getResources().getBoolean(
1868                             R.bool.config_bg_current_drain_event_duration_based_threshold_enabled));
1869             bgCurrentDrainEventDurationBasedThresholdEnabled.set(true);
1870 
1871             bgBatteryExemptionEnabled = new DeviceConfigSession<>(
1872                     DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
1873                     AppBatteryExemptionPolicy.KEY_BG_BATTERY_EXEMPTION_ENABLED,
1874                     DeviceConfig::getBoolean,
1875                     AppBatteryExemptionPolicy.DEFAULT_BG_BATTERY_EXEMPTION_ENABLED);
1876             bgBatteryExemptionEnabled.set(false);
1877 
1878             bgBatteryExemptionTypes = new DeviceConfigSession<>(
1879                     DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
1880                     AppBatteryPolicy.KEY_BG_CURRENT_DRAIN_EXEMPTED_TYPES,
1881                     DeviceConfig::getInt,
1882                     mContext.getResources().getInteger(
1883                             R.integer.config_bg_current_drain_exempted_types));
1884             bgBatteryExemptionTypes.set(STATE_TYPE_MEDIA_SESSION | STATE_TYPE_FGS_MEDIA_PLAYBACK
1885                     | STATE_TYPE_FGS_LOCATION | STATE_TYPE_PERMISSION
1886                     | STATE_TYPE_FGS_WITH_NOTIFICATION);
1887 
1888             bgPermissionMonitorEnabled = new DeviceConfigSession<>(
1889                     DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
1890                     AppPermissionPolicy.KEY_BG_PERMISSION_MONITOR_ENABLED,
1891                     DeviceConfig::getBoolean,
1892                     AppPermissionPolicy.DEFAULT_BG_PERMISSION_MONITOR_ENABLED);
1893             bgPermissionMonitorEnabled.set(true);
1894 
1895             bgPermissionsInMonitor = new DeviceConfigSession<>(
1896                     DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
1897                     AppPermissionPolicy.KEY_BG_PERMISSION_MONITOR_ENABLED,
1898                     DeviceConfig::getString,
1899                     Arrays.stream(AppPermissionPolicy.DEFAULT_BG_PERMISSIONS_IN_MONITOR)
1900                     .collect(Collectors.joining(",")));
1901             bgPermissionsInMonitor.set(ACCESS_FINE_LOCATION);
1902 
1903             bgCurrentDrainHighThresholdByBgLocation = new DeviceConfigSession<>(
1904                     DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
1905                     AppBatteryPolicy.KEY_BG_CURRENT_DRAIN_HIGH_THRESHOLD_BY_BG_LOCATION,
1906                     DeviceConfig::getBoolean,
1907                     mContext.getResources().getBoolean(
1908                             R.bool.config_bg_current_drain_high_threshold_by_bg_location));
1909             bgCurrentDrainHighThresholdByBgLocation.set(true);
1910 
1911             bgCurrentDrainDecoupleThresholds = new DeviceConfigSession<>(
1912                     DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
1913                     AppBatteryPolicy.KEY_BG_CURRENT_DRAIN_DECOUPLE_THRESHOLDS,
1914                     DeviceConfig::getBoolean,
1915                     AppBatteryPolicy.DEFAULT_BG_CURRENT_DRAIN_DECOUPLE_THRESHOLD);
1916             bgCurrentDrainDecoupleThresholds.set(true);
1917 
1918             bgPromptAbusiveAppToBgRestricted = new DeviceConfigSession<>(
1919                     DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
1920                     ConstantsObserver.KEY_BG_PROMPT_ABUSIVE_APPS_TO_BG_RESTRICTED,
1921                     DeviceConfig::getBoolean,
1922                     mContext.getResources().getBoolean(
1923                             R.bool.config_bg_prompt_abusive_apps_to_bg_restricted));
1924             bgPromptAbusiveAppToBgRestricted.set(true);
1925 
1926             mCurrentTimeMillis = 10_000L;
1927             doReturn(mCurrentTimeMillis - windowMs).when(stats).getStatsStartTimestamp();
1928             doReturn(mCurrentTimeMillis).when(stats).getStatsEndTimestamp();
1929             doReturn(statsList).when(mBatteryStatsInternal).getBatteryUsageStats(anyObject());
1930 
1931             // Run with a media playback service which starts/stops immediately, we should
1932             // goto the restricted bucket.
1933             runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
1934                     FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK, 0, true, false,
1935                     null, OP_NONE, null, null, listener, stats, uids,
1936                     new double[]{restrictBucketThresholdMah + 1, 0},
1937                     new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
1938                     false, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, true,
1939                     null, windowMs, null, null, null, null);
1940 
1941             // Run with a media playback service with extended time. We should be back to normal.
1942             runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
1943                     FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK, bgMediaPlaybackMinDuration * 2, false,
1944                     false, null, OP_NONE, null, null, listener, stats, uids,
1945                     new double[]{restrictBucketThresholdMah + 1, 0},
1946                     new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
1947                     true, RESTRICTION_LEVEL_ADAPTIVE_BUCKET, timeout, false,
1948                     () -> {
1949                         // A user interaction will bring it back to normal.
1950                         mIdleStateListener.onUserInteractionStarted(testPkgName1,
1951                                 UserHandle.getUserId(testUid1));
1952                         waitForIdleHandler(mBgRestrictionController.getBackgroundHandler());
1953                         // It should have been back to normal.
1954                         listener.verify(timeout, testUid1, testPkgName1,
1955                                 RESTRICTION_LEVEL_ADAPTIVE_BUCKET);
1956                         verify(mInjector.getAppStandbyInternal(), times(1)).maybeUnrestrictApp(
1957                                 eq(testPkgName1),
1958                                 eq(UserHandle.getUserId(testUid1)),
1959                                 eq(REASON_MAIN_FORCED_BY_SYSTEM),
1960                                 eq(REASON_SUB_FORCED_SYSTEM_FLAG_ABUSE),
1961                                 eq(REASON_MAIN_USAGE),
1962                                 eq(REASON_SUB_USAGE_USER_INTERACTION));
1963                     }, windowMs, null, null, null, null);
1964 
1965             // Start over.
1966             resetBgRestrictionController();
1967             setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros, zeros);
1968             mAppBatteryPolicy.reset();
1969 
1970             // Run with a media playback service with extended time, with higher current drain.
1971             runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
1972                     FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK, bgMediaPlaybackMinDuration * 2, false,
1973                     false, null, OP_NONE, null, null, listener, stats, uids,
1974                     new double[]{restrictBucketHighThresholdMah - 1, 0},
1975                     new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
1976                     true, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, true,
1977                     null, windowMs, null, null, null, null);
1978 
1979             // Run with a media playback service with extended time, with even higher current drain.
1980             runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
1981                     FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK, bgMediaPlaybackMinDuration * 2, false,
1982                     false, null, OP_NONE, null, null, listener, stats, uids,
1983                     new double[]{restrictBucketHighThresholdMah + 1, 0},
1984                     new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
1985                     false, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, false,
1986                     null, windowMs, null, null, null, null);
1987 
1988             // Start over.
1989             resetBgRestrictionController();
1990             setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros, zeros);
1991             mAppBatteryPolicy.reset();
1992 
1993             // Run with a media session with extended time, with higher current drain.
1994             runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
1995                     FOREGROUND_SERVICE_TYPE_NONE, bgMediaPlaybackMinDuration * 2, false, false,
1996                     null, OP_NONE,
1997                     List.of(Pair.create(createMediaControllers(new String[] {testPkgName1},
1998                           new int[] {testUid1}), bgMediaPlaybackMinDuration * 2)),
1999                     null, listener, stats, uids,
2000                     new double[]{restrictBucketHighThresholdMah - 1, 0},
2001                     new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
2002                     true, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, true,
2003                     null, windowMs, null, null, null, null);
2004 
2005             // Run with a media session with extended time, with even higher current drain.
2006             runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
2007                     FOREGROUND_SERVICE_TYPE_NONE, bgMediaPlaybackMinDuration * 2, false, false,
2008                     null, OP_NONE,
2009                     List.of(Pair.create(createMediaControllers(new String[] {testPkgName1},
2010                           new int[] {testUid1}), bgMediaPlaybackMinDuration * 2)),
2011                     null, listener, stats, uids,
2012                     new double[]{restrictBucketHighThresholdMah + 1, 0},
2013                     new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
2014                     false, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, false,
2015                     null, windowMs, null, null, null, null);
2016 
2017             // Start over.
2018             resetBgRestrictionController();
2019             setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros, zeros);
2020             mAppBatteryPolicy.reset();
2021 
2022             // Run with a media session with extended time, with moderate current drain,
2023             // but it ran on the top when the location service is active.
2024             runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
2025                     FOREGROUND_SERVICE_TYPE_NONE, bgMediaPlaybackMinDuration * 2, false, false,
2026                     null, OP_NONE,
2027                     List.of(Pair.create(createMediaControllers(new String[] {testPkgName1},
2028                           new int[] {testUid1}), bgMediaPlaybackMinDuration * 2)),
2029                     List.of(0L, timeout * 2), listener, stats, uids,
2030                     new double[]{restrictBucketThresholdMah + 1, 0},
2031                     new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
2032                     false, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, true,
2033                     null, windowMs, null, null, null, null);
2034 
2035             // Start over.
2036             resetBgRestrictionController();
2037             setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros, zeros);
2038             mAppBatteryPolicy.reset();
2039 
2040             // Run with a location service with extended time, with higher current drain.
2041             runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
2042                     FOREGROUND_SERVICE_TYPE_LOCATION, bgMediaPlaybackMinDuration * 2, false, false,
2043                     null, OP_NONE, null, null, listener, stats, uids,
2044                     new double[]{restrictBucketHighThresholdMah - 1, 0},
2045                     new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
2046                     true, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, true,
2047                     null, windowMs, null, null, null, null);
2048 
2049             // Run with a location service with extended time, with even higher current drain.
2050             runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
2051                     FOREGROUND_SERVICE_TYPE_LOCATION, bgMediaPlaybackMinDuration * 2, false, false,
2052                     null, OP_NONE, null, null, listener, stats, uids,
2053                     new double[]{restrictBucketHighThresholdMah + 1, 0},
2054                     new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
2055                     false, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, false,
2056                     null, windowMs, null, null, null, null);
2057 
2058             // Start over.
2059             resetBgRestrictionController();
2060             setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros, zeros);
2061             mAppBatteryPolicy.reset();
2062 
2063             // Run with a location service with extended time, with moderate current drain,
2064             // but it ran on the top when the location service is active.
2065             runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
2066                     FOREGROUND_SERVICE_TYPE_LOCATION, bgMediaPlaybackMinDuration * 2, false, false,
2067                     null, OP_NONE, null, List.of(0L, timeout * 2), listener, stats, uids,
2068                     new double[]{restrictBucketThresholdMah + 1, 0},
2069                     new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
2070                     false, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, true,
2071                     null, windowMs, null, null, null, null);
2072 
2073             // Start over.
2074             resetBgRestrictionController();
2075             setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros, zeros);
2076             mAppBatteryPolicy.reset();
2077 
2078             // Turn off the higher threshold for bg location access.
2079             bgCurrentDrainHighThresholdByBgLocation.set(false);
2080 
2081             // Run with bg location permission, with moderate current drain.
2082             runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
2083                     FOREGROUND_SERVICE_TYPE_NONE, 0, false, false,
2084                     ACCESS_BACKGROUND_LOCATION, OP_NONE, null, null, listener, stats, uids,
2085                     new double[]{restrictBucketThresholdMah - 1, 0},
2086                     new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
2087                     true, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, true,
2088                     null, windowMs, null, null, null, null);
2089 
2090             // Run with bg location permission, with a bit higher current drain.
2091             runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
2092                     FOREGROUND_SERVICE_TYPE_NONE, 0, false, false,
2093                     ACCESS_BACKGROUND_LOCATION, OP_NONE, null, null, listener, stats, uids,
2094                     new double[]{restrictBucketThresholdMah + 1, 0},
2095                     new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
2096                     false, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, true,
2097                     null, windowMs, null, null, null, null);
2098 
2099             // Start over.
2100             resetBgRestrictionController();
2101             setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros, zeros);
2102             mAppBatteryPolicy.reset();
2103 
2104             // Turn on the higher threshold for bg location access.
2105             bgCurrentDrainHighThresholdByBgLocation.set(true);
2106 
2107             // Run with bg location permission, with higher current drain.
2108             runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
2109                     FOREGROUND_SERVICE_TYPE_NONE, 0, false, false,
2110                     ACCESS_BACKGROUND_LOCATION, OP_NONE, null, null, listener, stats, uids,
2111                     new double[]{restrictBucketHighThresholdMah - 1, 0},
2112                     new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
2113                     true , RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, false,
2114                     null, windowMs, null,  null, null, null);
2115 
2116             // Run with bg location permission, with even higher current drain.
2117             runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
2118                     FOREGROUND_SERVICE_TYPE_NONE, 0, false, false,
2119                     ACCESS_BACKGROUND_LOCATION, OP_NONE, null, null, listener, stats, uids,
2120                     new double[]{restrictBucketHighThresholdMah + 1, 0},
2121                     new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
2122                     false, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, false,
2123                     null, windowMs, null,  null, null, null);
2124 
2125             // Now turn off the event duration based feature flag.
2126             bgCurrentDrainEventDurationBasedThresholdEnabled.set(false);
2127             // Turn on the battery exemption feature flag.
2128             bgBatteryExemptionEnabled.set(true);
2129 
2130             // Start over.
2131             resetBgRestrictionController();
2132             setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros, zeros);
2133             mAppBatteryPolicy.reset();
2134 
2135             waitForIdleHandler(mBgRestrictionController.getBackgroundHandler());
2136 
2137             // Run with a media playback service which starts/stops immediately, we should
2138             // goto the restricted bucket.
2139             runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
2140                     FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK, 0, true, false,
2141                     null, OP_NONE, null, null, listener, stats, uids,
2142                     new double[]{restrictBucketThresholdMah + 1, 0},
2143                     new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
2144                     false, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, true,
2145                     null, windowMs, null, null, null, null);
2146 
2147             // Run with a media playback service with extended time. We should be back to normal.
2148             runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
2149                     FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK, bgMediaPlaybackMinDuration * 2, false,
2150                     false, null, OP_NONE, null, null, listener, stats, uids,
2151                     new double[]{restrictBucketThresholdMah + 1, 0},
2152                     new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
2153                     true, RESTRICTION_LEVEL_ADAPTIVE_BUCKET, timeout, false,
2154                     () -> {
2155                         // A user interaction will bring it back to normal.
2156                         mIdleStateListener.onUserInteractionStarted(testPkgName1,
2157                                 UserHandle.getUserId(testUid1));
2158                         waitForIdleHandler(mBgRestrictionController.getBackgroundHandler());
2159                         // It should have been back to normal.
2160                         listener.verify(timeout, testUid1, testPkgName1,
2161                                 RESTRICTION_LEVEL_ADAPTIVE_BUCKET);
2162                         verify(mInjector.getAppStandbyInternal(), times(1)).maybeUnrestrictApp(
2163                                 eq(testPkgName1),
2164                                 eq(UserHandle.getUserId(testUid1)),
2165                                 eq(REASON_MAIN_FORCED_BY_SYSTEM),
2166                                 eq(REASON_SUB_FORCED_SYSTEM_FLAG_ABUSE),
2167                                 eq(REASON_MAIN_USAGE),
2168                                 eq(REASON_SUB_USAGE_USER_INTERACTION));
2169                     }, windowMs, null, null, null, null);
2170 
2171             // Start over.
2172             resetBgRestrictionController();
2173             setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros, zeros);
2174             mAppBatteryPolicy.reset();
2175 
2176             final double[] initialBg = {1, 1}, initialFgs = {1, 1}, initialFg = zeros,
2177                     initialCached = {1, 1};
2178 
2179             // Run with a media playback service with extended time, with higher current drain.
2180             runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
2181                     FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK, bgMediaPlaybackMinDuration * 2, false,
2182                     false, null, OP_NONE, null, null, listener, stats, uids,
2183                     new double[]{restrictBucketHighThresholdMah - 1, 0},
2184                     new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
2185                     true, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, true,
2186                     null, windowMs, initialBg, initialFgs, initialFg, initialCached);
2187 
2188             // Run with a media playback service with extended time, with even higher current drain,
2189             // it still should stay in the current restriction level as we exempt the media
2190             // playback.
2191             runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
2192                     FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK, bgMediaPlaybackMinDuration * 2, false,
2193                     false, null, OP_NONE, null, null, listener, stats, uids,
2194                     new double[]{restrictBucketHighThresholdMah + 100, 0},
2195                     new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
2196                     true, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, false,
2197                     null, windowMs, initialBg, initialFgs, initialFg, initialCached);
2198 
2199             // Set the policy to exempt media session and permission.
2200             bgBatteryExemptionTypes.set(STATE_TYPE_MEDIA_SESSION | STATE_TYPE_PERMISSION);
2201             // Start over.
2202             resetBgRestrictionController();
2203             setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros, zeros);
2204             mAppBatteryPolicy.reset();
2205 
2206             // Run with coarse location permission, with high current drain.
2207             runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
2208                     FOREGROUND_SERVICE_TYPE_NONE, 0, false, false,
2209                     ACCESS_COARSE_LOCATION, OP_NONE, null, null, listener, stats, uids,
2210                     new double[]{restrictBucketThresholdMah + 1, 0},
2211                     new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
2212                     false, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, true,
2213                     null, windowMs, initialBg, initialFgs, initialFg, initialCached);
2214 
2215             // Start over.
2216             resetBgRestrictionController();
2217             setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros, zeros);
2218             mAppBatteryPolicy.reset();
2219 
2220             // Run with fine location permission, with high current drain.
2221             runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
2222                     FOREGROUND_SERVICE_TYPE_NONE, 0, false, false,
2223                     ACCESS_FINE_LOCATION, OP_FINE_LOCATION, null, null, listener, stats, uids,
2224                     new double[]{restrictBucketThresholdMah + 1, 0},
2225                     new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
2226                     true, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, true,
2227                     null, windowMs, initialBg, initialFgs, initialFg, initialCached);
2228 
2229             // Start over.
2230             resetBgRestrictionController();
2231             setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros, zeros);
2232             mAppBatteryPolicy.reset();
2233 
2234             // Run with a media session with extended time, with higher current drain.
2235             runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
2236                     FOREGROUND_SERVICE_TYPE_NONE, bgMediaPlaybackMinDuration * 2, false, false,
2237                     null, OP_NONE,
2238                     List.of(Pair.create(createMediaControllers(new String[] {testPkgName1},
2239                           new int[] {testUid1}), bgMediaPlaybackMinDuration * 2)),
2240                     null, listener, stats, uids,
2241                     new double[]{restrictBucketHighThresholdMah - 1, 0},
2242                     new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
2243                     true, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, true,
2244                     null, windowMs, initialBg, initialFgs, initialFg, initialCached);
2245 
2246             // Run with a media session with extended time, with even higher current drain.
2247             // it still should stay in the current restriction level as we exempt the media
2248             // session.
2249             runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
2250                     FOREGROUND_SERVICE_TYPE_NONE, bgMediaPlaybackMinDuration * 2, false, false,
2251                     null, OP_NONE,
2252                     List.of(Pair.create(createMediaControllers(new String[] {testPkgName1},
2253                           new int[] {testUid1}), bgMediaPlaybackMinDuration * 2)),
2254                     null, listener, stats, uids,
2255                     new double[]{restrictBucketHighThresholdMah + 100, 0},
2256                     new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
2257                     true, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, true,
2258                     null, windowMs, initialBg, initialFgs, initialFg, initialCached);
2259 
2260             // Set the policy to exempt fgs with notifications.
2261             bgBatteryExemptionTypes.set(STATE_TYPE_FGS_WITH_NOTIFICATION);
2262             // Start over.
2263             resetBgRestrictionController();
2264             setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros, zeros);
2265             mAppBatteryPolicy.reset();
2266 
2267             // Run with a FGS with notification posted/removed immediately, we should
2268             // goto the restricted bucket.
2269             runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
2270                     FOREGROUND_SERVICE_TYPE_NONE, 0, true, true,
2271                     null, OP_NONE, null, null, listener, stats, uids,
2272                     new double[]{restrictBucketThresholdMah + 1, 0},
2273                     new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
2274                     false, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, true,
2275                     null, windowMs, null, null, null, null);
2276 
2277             // Run with a service with notification for extended time. We should be back to normal.
2278             runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
2279                     FOREGROUND_SERVICE_TYPE_NONE, bgMediaPlaybackMinDuration * 2, false,
2280                     true, null, OP_NONE, null, null, listener, stats, uids,
2281                     new double[]{restrictBucketThresholdMah + 1, 0},
2282                     new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
2283                     true, RESTRICTION_LEVEL_ADAPTIVE_BUCKET, timeout, false,
2284                     () -> {
2285                         // A user interaction will bring it back to normal.
2286                         mIdleStateListener.onUserInteractionStarted(testPkgName1,
2287                                 UserHandle.getUserId(testUid1));
2288                         waitForIdleHandler(mBgRestrictionController.getBackgroundHandler());
2289                         // It should have been back to normal.
2290                         listener.verify(timeout, testUid1, testPkgName1,
2291                                 RESTRICTION_LEVEL_ADAPTIVE_BUCKET);
2292                         verify(mInjector.getAppStandbyInternal(), times(1)).maybeUnrestrictApp(
2293                                 eq(testPkgName1),
2294                                 eq(UserHandle.getUserId(testUid1)),
2295                                 eq(REASON_MAIN_FORCED_BY_SYSTEM),
2296                                 eq(REASON_SUB_FORCED_SYSTEM_FLAG_ABUSE),
2297                                 eq(REASON_MAIN_USAGE),
2298                                 eq(REASON_SUB_USAGE_USER_INTERACTION));
2299                     }, windowMs, null, null, null, null);
2300 
2301             // Set the policy to exempt all.
2302             bgBatteryExemptionTypes.set(STATE_TYPE_MEDIA_SESSION | STATE_TYPE_FGS_MEDIA_PLAYBACK
2303                     | STATE_TYPE_FGS_LOCATION | STATE_TYPE_PERMISSION
2304                     | STATE_TYPE_FGS_WITH_NOTIFICATION);
2305 
2306             // Start over.
2307             resetBgRestrictionController();
2308             setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros, zeros);
2309             mAppBatteryPolicy.reset();
2310 
2311             // Run with a location service with extended time, with higher current drain.
2312             runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
2313                     FOREGROUND_SERVICE_TYPE_LOCATION, bgMediaPlaybackMinDuration * 2, false, false,
2314                     null, OP_NONE, null, null, listener, stats, uids,
2315                     new double[]{restrictBucketHighThresholdMah - 1, 0},
2316                     new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
2317                     true, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, true,
2318                     null, windowMs, initialBg, initialFgs, initialFg, initialCached);
2319 
2320             // Run with a location service with extended time, with even higher current drain.
2321             // it still should stay in the current restriction level as we exempt the location.
2322             runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
2323                     FOREGROUND_SERVICE_TYPE_LOCATION, bgMediaPlaybackMinDuration * 2, false, false,
2324                     null, OP_NONE, null, null, listener, stats, uids,
2325                     new double[]{restrictBucketHighThresholdMah + 100, 0},
2326                     new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
2327                     true, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, false,
2328                     null, windowMs, initialBg, initialFgs, initialFg, initialCached);
2329         } finally {
2330             closeIfNotNull(bgCurrentDrainMonitor);
2331             closeIfNotNull(bgCurrentDrainWindow);
2332             closeIfNotNull(bgCurrentDrainInteractionGracePeriod);
2333             closeIfNotNull(bgCurrentDrainRestrictedBucketThreshold);
2334             closeIfNotNull(bgCurrentDrainBgRestrictedThreshold);
2335             closeIfNotNull(bgCurrentDrainRestrictedBucketHighThreshold);
2336             closeIfNotNull(bgCurrentDrainBgRestrictedHighThreshold);
2337             closeIfNotNull(bgCurrentDrainAutoRestrictAbusiveApps);
2338             closeIfNotNull(bgMediaPlaybackMinDurationThreshold);
2339             closeIfNotNull(bgLocationMinDurationThreshold);
2340             closeIfNotNull(bgCurrentDrainEventDurationBasedThresholdEnabled);
2341             closeIfNotNull(bgBatteryExemptionEnabled);
2342             closeIfNotNull(bgBatteryExemptionTypes);
2343             closeIfNotNull(bgPermissionMonitorEnabled);
2344             closeIfNotNull(bgPermissionsInMonitor);
2345             closeIfNotNull(bgPromptAbusiveAppToBgRestricted);
2346             closeIfNotNull(bgCurrentDrainHighThresholdByBgLocation);
2347             closeIfNotNull(bgCurrentDrainDecoupleThresholds);
2348         }
2349     }
2350 
runTestBgCurrentDrainExemptionOnce(String packageName, int uid, int pid, int serviceType, long sleepMs, boolean stopAfterSleep, boolean withNotification, String perm, int op, List<Pair<List<MediaController>, Long>> mediaControllers, List<Long> topStateChanges, TestAppRestrictionLevelListener listener, BatteryUsageStats stats, int[] uids, double[] bg, double[] fgs, double[] fg, double[] cached, boolean expectingTimeout, int expectingLevel, long timeout, boolean resetFGSTracker, RunnableWithException extraVerifiers, long windowMs, double[] initialBg, double[] initialFgs, double[] initialFg, double[] initialCached)2351     private void runTestBgCurrentDrainExemptionOnce(String packageName, int uid, int pid,
2352             int serviceType, long sleepMs, boolean stopAfterSleep, boolean withNotification,
2353             String perm, int op, List<Pair<List<MediaController>, Long>> mediaControllers,
2354             List<Long> topStateChanges, TestAppRestrictionLevelListener listener,
2355             BatteryUsageStats stats, int[] uids, double[] bg, double[] fgs, double[] fg,
2356             double[] cached, boolean expectingTimeout, int expectingLevel, long timeout,
2357             boolean resetFGSTracker, RunnableWithException extraVerifiers, long windowMs,
2358             double[] initialBg, double[] initialFgs, double[] initialFg, double[] initialCached)
2359             throws Exception {
2360         listener.mLatchHolder[0] = new CountDownLatch(1);
2361         if (initialBg != null) {
2362             doReturn(mCurrentTimeMillis).when(stats).getStatsStartTimestamp();
2363             doReturn(mCurrentTimeMillis + windowMs).when(stats).getStatsEndTimestamp();
2364             mCurrentTimeMillis += windowMs + 1;
2365             setUidBatteryConsumptions(stats, uids, initialBg, initialFgs, initialFg, initialCached);
2366             mAppBatteryExemptionTracker.reset();
2367             mAppBatteryPolicy.reset();
2368         }
2369         if (perm != null) {
2370             setPermissionState(packageName, uid, perm, true);
2371             if (op != OP_NONE) {
2372                 setAppOpState(packageName, uid, op, true);
2373             }
2374             mInjector.getAppPermissionTracker().onPermissionsChanged(uid);
2375         }
2376         waitForIdleHandler(mBgRestrictionController.getBackgroundHandler());
2377         runExemptionTestOnce(
2378                 packageName, uid, pid, serviceType, sleepMs, stopAfterSleep, withNotification,
2379                 perm, op, mediaControllers, topStateChanges, resetFGSTracker, false,
2380                 () -> {
2381                     clearInvocations(mInjector.getAppStandbyInternal());
2382                     clearInvocations(mBgRestrictionController);
2383                     runTestBgCurrentDrainMonitorOnce(listener, stats, uids, bg, fgs, fg, cached,
2384                             false, () -> {
2385                                 doReturn(mCurrentTimeMillis).when(stats).getStatsStartTimestamp();
2386                                 doReturn(mCurrentTimeMillis + windowMs)
2387                                         .when(stats).getStatsEndTimestamp();
2388                                 mCurrentTimeMillis += windowMs + 1;
2389                                 if (expectingTimeout) {
2390                                     try {
2391                                         listener.verify(timeout, uid, packageName, expectingLevel);
2392                                         fail("There shouldn't be any level change events");
2393                                     } catch (Exception e) {
2394                                         // Expected.
2395                                     }
2396                                 } else {
2397                                     listener.verify(timeout, uid, packageName, expectingLevel);
2398                                 }
2399                                 if (expectingLevel == RESTRICTION_LEVEL_RESTRICTED_BUCKET) {
2400                                     verify(mInjector.getAppStandbyInternal(),
2401                                             expectingTimeout ? never() : atLeast(1)).restrictApp(
2402                                             eq(packageName),
2403                                             eq(UserHandle.getUserId(uid)),
2404                                             anyInt(), anyInt());
2405                                 } else if (expectingLevel
2406                                          == RESTRICTION_LEVEL_BACKGROUND_RESTRICTED) {
2407                                     verify(mBgRestrictionController,
2408                                             expectingTimeout ? never() : atLeast(1))
2409                                             .handleRequestBgRestricted(eq(packageName), eq(uid));
2410                                 } else {
2411                                     verify(mInjector.getAppStandbyInternal(),
2412                                             expectingTimeout ? never() : atLeast(1))
2413                                             .setAppStandbyBucket(
2414                                                    eq(packageName),
2415                                                    eq(STANDBY_BUCKET_RARE),
2416                                                    eq(UserHandle.getUserId(uid)),
2417                                                    anyInt(), anyInt());
2418                                 }
2419                                 if (extraVerifiers != null) {
2420                                     extraVerifiers.run();
2421                                 }
2422                             }
2423                     );
2424                 }
2425         );
2426         if (perm != null) {
2427             setPermissionState(packageName, uid, perm, false);
2428             if (op != OP_NONE) {
2429                 setAppOpState(packageName, uid, op, false);
2430             }
2431             mInjector.getAppPermissionTracker().onPermissionsChanged(uid);
2432         }
2433     }
2434 
setPermissionState(String packageName, int uid, String perm, boolean granted)2435     private void setPermissionState(String packageName, int uid, String perm, boolean granted) {
2436         doReturn(granted ? PERMISSION_GRANTED : PERMISSION_DENIED)
2437                 .when(mPermissionManagerServiceInternal)
2438                 .checkUidPermission(uid, perm);
2439         doReturn(granted ? PERMISSION_GRANTED : PERMISSION_DENIED)
2440                 .when(mPermissionManagerServiceInternal)
2441                 .checkPermission(packageName, perm, UserHandle.getUserId(uid));
2442     }
2443 
setAppOpState(String packageName, int uid, int op, boolean granted)2444     private void setAppOpState(String packageName, int uid, int op, boolean granted) {
2445         try {
2446             doReturn(granted ? MODE_ALLOWED : MODE_IGNORED)
2447                     .when(mAppOpsManager)
2448                     .checkOpNoThrow(op, uid, packageName);
2449             doReturn(granted ? MODE_ALLOWED : MODE_IGNORED)
2450                     .when(mIAppOpsService)
2451                     .checkOperation(op, uid, packageName);
2452         } catch (RemoteException e) {
2453             // Ignore.
2454         }
2455     }
2456 
2457     @Test
testExcessiveBroadcasts()2458     public void testExcessiveBroadcasts() throws Exception {
2459         final long windowMs = 5_000;
2460         final int threshold = 10;
2461         runTestExcessiveEvent(AppBroadcastEventsPolicy.KEY_BG_BROADCAST_MONITOR_ENABLED,
2462                 AppBroadcastEventsPolicy.DEFAULT_BG_BROADCAST_MONITOR_ENABLED,
2463                 AppBroadcastEventsPolicy.KEY_BG_BROADCAST_WINDOW,
2464                 AppBroadcastEventsPolicy.DEFAULT_BG_BROADCAST_WINDOW,
2465                 AppBroadcastEventsPolicy.KEY_BG_EX_BROADCAST_THRESHOLD,
2466                 AppBroadcastEventsPolicy.DEFAULT_BG_EX_BROADCAST_THRESHOLD,
2467                 windowMs, threshold, mBroadcastEventListener::onSendingBroadcast,
2468                 mAppBroadcastEventsTracker,
2469                 new long[][] {
2470                     new long[] {1_000L, 2_000L, 2_000L},
2471                     new long[] {2_000L, 2_000L, 1_000L},
2472                 },
2473                 new int[][] {
2474                     new int[] {3, 3, 3},
2475                     new int[] {3, 3, 4},
2476                 },
2477                 new boolean[] {
2478                     true,
2479                     false,
2480                 }
2481         );
2482     }
2483 
2484     @Test
testExcessiveBindServices()2485     public void testExcessiveBindServices() throws Exception {
2486         final long windowMs = 5_000;
2487         final int threshold = 10;
2488         runTestExcessiveEvent(AppBindServiceEventsPolicy.KEY_BG_BIND_SVC_MONITOR_ENABLED,
2489                 AppBindServiceEventsPolicy.DEFAULT_BG_BIND_SVC_MONITOR_ENABLED,
2490                 AppBindServiceEventsPolicy.KEY_BG_BIND_SVC_WINDOW,
2491                 AppBindServiceEventsPolicy.DEFAULT_BG_BIND_SVC_WINDOW,
2492                 AppBindServiceEventsPolicy.KEY_BG_EX_BIND_SVC_THRESHOLD,
2493                 AppBindServiceEventsPolicy.DEFAULT_BG_EX_BIND_SVC_THRESHOLD,
2494                 windowMs, threshold, mBindServiceEventListener::onBindingService,
2495                 mAppBindServiceEventsTracker,
2496                 new long[][] {
2497                     new long[] {0L, 2_000L, 4_000L, 1_000L},
2498                     new long[] {2_000L, 2_000L, 2_000L, 2_000L},
2499                 },
2500                 new int[][] {
2501                     new int[] {8, 3, 1, 0}, // Will goto restricted bucket.
2502                     new int[] {3, 3, 3, 3},
2503                 },
2504                 new boolean[] {
2505                     false,
2506                     true,
2507                 }
2508         );
2509     }
2510 
runTestExcessiveEvent(String keyEnable, boolean defaultEnable, String keyWindow, long defaultWindow, String keyThreshold, int defaultThreshold, long windowMs, int threshold, BiConsumer<String, Integer> eventEmitter, BaseAppStateEventsTracker tracker, long[][] waitMs, int[][] events, boolean[] expectingTimeout)2511     private void runTestExcessiveEvent(String keyEnable, boolean defaultEnable,
2512             String keyWindow, long defaultWindow, String keyThreshold, int defaultThreshold,
2513             long windowMs, int threshold, BiConsumer<String, Integer> eventEmitter,
2514             BaseAppStateEventsTracker tracker, long[][] waitMs, int[][] events,
2515             boolean[] expectingTimeout) throws Exception {
2516         final int testPkgIndex = 1;
2517         final String testPkgName = TEST_PACKAGE_BASE + testPkgIndex;
2518         final int testUser = TEST_USER0;
2519         final int testUid = UserHandle.getUid(testUser, TEST_PACKAGE_APPID_BASE + testPkgIndex);
2520         final int testPid = 1234;
2521 
2522         final long timeoutMs = 2_000;
2523 
2524         final TestAppRestrictionLevelListener listener = new TestAppRestrictionLevelListener();
2525 
2526         mBgRestrictionController.addAppBackgroundRestrictionListener(listener);
2527         setBackgroundRestrict(testPkgName, testUid, false, listener);
2528 
2529         DeviceConfigSession<Boolean> enableMonitor = null;
2530         DeviceConfigSession<Long> eventsWindow = null;
2531         DeviceConfigSession<Integer> eventsThreshold = null;
2532 
2533         doReturn(testPkgName).when(mInjector).getPackageName(testPid);
2534 
2535         verifyRestrictionLevel(RESTRICTION_LEVEL_ADAPTIVE_BUCKET, testPkgName, testUid);
2536 
2537         try {
2538             enableMonitor = new DeviceConfigSession<>(
2539                     DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
2540                     keyEnable,
2541                     DeviceConfig::getBoolean,
2542                     defaultEnable);
2543             enableMonitor.set(true);
2544 
2545             eventsWindow = new DeviceConfigSession<>(
2546                     DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
2547                     keyWindow,
2548                     DeviceConfig::getLong,
2549                     defaultWindow);
2550             eventsWindow.set(windowMs);
2551 
2552             eventsThreshold = new DeviceConfigSession<>(
2553                     DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
2554                     keyThreshold,
2555                     DeviceConfig::getInt,
2556                     defaultThreshold);
2557             eventsThreshold.set(threshold);
2558 
2559             for (int i = 0; i < waitMs.length; i++) {
2560                 resetBgRestrictionController();
2561                 listener.mLatchHolder[0] = new CountDownLatch(1);
2562                 tracker.reset();
2563                 clearInvocations(mInjector.getAppStandbyInternal());
2564                 clearInvocations(mBgRestrictionController);
2565                 for (int j = 0; j < waitMs[i].length; j++) {
2566                     for (int k = 0; k < events[i][j]; k++) {
2567                         eventEmitter.accept(testPkgName, testUid);
2568                     }
2569                     Thread.sleep(waitMs[i][j]);
2570                 }
2571                 waitForIdleHandler(mBgRestrictionController.getBackgroundHandler());
2572                 if (expectingTimeout[i]) {
2573                     verifyRestrictionLevel(RESTRICTION_LEVEL_ADAPTIVE_BUCKET, testPkgName, testUid);
2574                     try {
2575                         listener.verify(timeoutMs, testUid, testPkgName,
2576                                 RESTRICTION_LEVEL_RESTRICTED_BUCKET);
2577                         fail("There shouldn't be any level change events");
2578                     } catch (TimeoutException e) {
2579                         // expected.
2580                     }
2581                 } else {
2582                     verifyRestrictionLevel(RESTRICTION_LEVEL_RESTRICTED_BUCKET,
2583                             testPkgName, testUid);
2584                     listener.verify(timeoutMs, testUid, testPkgName,
2585                             RESTRICTION_LEVEL_RESTRICTED_BUCKET);
2586                 }
2587             }
2588         } finally {
2589             closeIfNotNull(enableMonitor);
2590             closeIfNotNull(eventsWindow);
2591             closeIfNotNull(eventsThreshold);
2592         }
2593     }
2594 
checkNotificationShown(String[] packageName, VerificationMode mode, boolean verifyNotification)2595     private int[] checkNotificationShown(String[] packageName, VerificationMode mode,
2596             boolean verifyNotification) throws Exception {
2597         final ArgumentCaptor<Integer> notificationIdCaptor =
2598                 ArgumentCaptor.forClass(Integer.class);
2599         final ArgumentCaptor<Notification> notificationCaptor =
2600                 ArgumentCaptor.forClass(Notification.class);
2601         verify(mInjector.getNotificationManager(), mode).notifyAsUser(any(),
2602                 notificationIdCaptor.capture(), notificationCaptor.capture(), any());
2603         final int[] notificationId = new int[packageName.length];
2604         if (verifyNotification) {
2605             for (int i = 0, j = 0; i < packageName.length; j++) {
2606                 final int id = notificationIdCaptor.getAllValues().get(j);
2607                 if (id == NotificationHelper.SUMMARY_NOTIFICATION_ID) {
2608                     continue;
2609                 }
2610                 final Notification n = notificationCaptor.getAllValues().get(j);
2611                 notificationId[i] = id;
2612                 assertTrue(NotificationHelper.SUMMARY_NOTIFICATION_ID < notificationId[i]);
2613                 assertEquals(NotificationHelper.GROUP_KEY, n.getGroup());
2614                 assertEquals(ABUSIVE_BACKGROUND_APPS, n.getChannelId());
2615                 assertEquals(packageName[i], n.extras.getString(Intent.EXTRA_PACKAGE_NAME));
2616                 i++;
2617             }
2618         }
2619         return notificationId;
2620     }
2621 
2622     private void checkNotificationGone(String packageName, VerificationMode mode,
2623             int notificationId) throws Exception {
2624         final ArgumentCaptor<Integer> notificationIdCaptor =
2625                 ArgumentCaptor.forClass(Integer.class);
2626         verify(mInjector.getNotificationManager(), mode).cancel(notificationIdCaptor.capture());
2627         assertEquals(notificationId, notificationIdCaptor.getValue().intValue());
2628     }
2629 
2630     private void closeIfNotNull(DeviceConfigSession<?> config) throws Exception {
2631         if (config != null) {
2632             config.close();
2633         }
2634     }
2635 
2636     private interface RunnableWithException {
2637         void run() throws Exception;
2638     }
2639 
2640     private void runTestBgCurrentDrainMonitorOnce(TestAppRestrictionLevelListener listener,
2641             BatteryUsageStats stats, int[] uids, double[] bg, double[] fgs, double[] fg,
2642             double[] cached, RunnableWithException runnable) throws Exception {
2643         runTestBgCurrentDrainMonitorOnce(listener, stats, uids, bg, fgs, fg, cached, true,
2644                 runnable);
2645     }
2646 
2647     private void runTestBgCurrentDrainMonitorOnce(TestAppRestrictionLevelListener listener,
2648             BatteryUsageStats stats, int[] uids, double[] bg, double[] fgs, double[] fg,
2649             double[] cached, boolean resetListener, RunnableWithException runnable)
2650             throws Exception {
2651         if (resetListener) {
2652             listener.mLatchHolder[0] = new CountDownLatch(1);
2653         }
2654         setUidBatteryConsumptions(stats, uids, bg, fgs, fg, cached);
2655         runnable.run();
2656     }
2657 
2658     private void setUidBatteryConsumptions(BatteryUsageStats stats, int[] uids, double[] bg,
2659             double[] fgs, double[] fg, double[] cached) {
2660         ArrayList<UidBatteryConsumer> consumers = new ArrayList<>();
2661         for (int i = 0; i < uids.length; i++) {
2662             consumers.add(mockUidBatteryConsumer(uids[i], bg[i], fgs[i], fg[i], cached[i]));
2663         }
2664         doReturn(consumers).when(stats).getUidBatteryConsumers();
2665     }
2666 
2667     private UidBatteryConsumer mockUidBatteryConsumer(int uid, double bg, double fgs, double fg,
2668             double cached) {
2669         UidBatteryConsumer uidConsumer = mock(UidBatteryConsumer.class);
2670         doReturn(uid).when(uidConsumer).getUid();
2671         doReturn(bg).when(uidConsumer).getConsumedPower(
2672                 eq(BATT_DIMENS[BATTERY_USAGE_INDEX_BACKGROUND]));
2673         doReturn(fgs).when(uidConsumer).getConsumedPower(
2674                 eq(BATT_DIMENS[BATTERY_USAGE_INDEX_FOREGROUND_SERVICE]));
2675         doReturn(fg).when(uidConsumer).getConsumedPower(
2676                 eq(BATT_DIMENS[BATTERY_USAGE_INDEX_FOREGROUND]));
2677         doReturn(cached).when(uidConsumer).getConsumedPower(
2678                 eq(BATT_DIMENS[BATTERY_USAGE_INDEX_CACHED]));
2679         return uidConsumer;
2680     }
2681 
2682     private void setBackgroundRestrict(String pkgName, int uid, boolean restricted,
2683             TestAppRestrictionLevelListener listener) throws Exception {
2684         Log.i(TAG, "Setting background restrict to " + restricted + " for " + pkgName + " " + uid);
2685         listener.mLatchHolder[0] = new CountDownLatch(1);
2686         doReturn(restricted).when(mAppStateTracker).isAppBackgroundRestricted(uid, pkgName);
2687         mFasListener.updateBackgroundRestrictedForUidPackage(uid, pkgName, restricted);
2688         waitForIdleHandler(mBgRestrictionController.getBackgroundHandler());
2689     }
2690 
2691     private class TestAppRestrictionLevelListener implements AppBackgroundRestrictionListener {
2692         private final CountDownLatch[] mLatchHolder = new CountDownLatch[1];
2693         final int[] mUidHolder = new int[1];
2694         final String[] mPkgNameHolder = new String[1];
2695         final int[] mLevelHolder = new int[1];
2696 
2697         @Override
2698         public void onRestrictionLevelChanged(int uid, String packageName, int newLevel) {
2699             mUidHolder[0] = uid;
2700             mPkgNameHolder[0] = packageName;
2701             mLevelHolder[0] = newLevel;
2702             mLatchHolder[0].countDown();
2703         };
2704 
2705         void verify(long timeout, int uid, String pkgName, int level) throws Exception {
2706             if (!mLatchHolder[0].await(timeout, TimeUnit.MILLISECONDS)) {
2707                 throw new TimeoutException();
2708             }
2709             assertEquals(uid, mUidHolder[0]);
2710             assertEquals(pkgName, mPkgNameHolder[0]);
2711             assertEquals(level, mLevelHolder[0]);
2712         }
2713     }
2714 
2715     private void verifyRestrictionLevel(int level, String pkgName, int uid) {
2716         assertEquals(level, mBgRestrictionController.getRestrictionLevel(uid));
2717         assertEquals(level, mBgRestrictionController.getRestrictionLevel(uid, pkgName));
2718     }
2719 
2720     private void waitForIdleHandler(Handler handler) {
2721         waitForIdleHandler(handler, Duration.ofSeconds(1));
2722     }
2723 
2724     private void waitForIdleHandler(Handler handler, Duration timeout) {
2725         final MessageQueue queue = handler.getLooper().getQueue();
2726         final CountDownLatch latch = new CountDownLatch(1);
2727         queue.addIdleHandler(() -> {
2728             latch.countDown();
2729             // Remove idle handler
2730             return false;
2731         });
2732         try {
2733             latch.await(timeout.toMillis(), TimeUnit.MILLISECONDS);
2734         } catch (InterruptedException e) {
2735             fail("Interrupted unexpectedly: " + e);
2736         }
2737     }
2738 
2739     @Test
2740     public void testMergeAppStateDurations() throws Exception {
2741         final BaseAppStateDurations testObj = new BaseAppStateDurations(0, "", 1, "", null) {};
2742         assertAppStateDurations(null, testObj.add(null, null));
2743         assertAppStateDurations(new LinkedList<BaseTimeEvent>(), testObj.add(
2744                 null, new LinkedList<BaseTimeEvent>()));
2745         assertAppStateDurations(new LinkedList<BaseTimeEvent>(), testObj.add(
2746                 new LinkedList<BaseTimeEvent>(), null));
2747         assertAppStateDurations(createDurations(1), testObj.add(
2748                 createDurations(1), new LinkedList<BaseTimeEvent>()));
2749         assertAppStateDurations(createDurations(1), testObj.add(
2750                 new LinkedList<BaseTimeEvent>(), createDurations(1)));
2751         assertAppStateDurations(createDurations(1, 4, 5, 8, 9), testObj.add(
2752                 createDurations(1, 3, 5, 7, 9), createDurations(2, 4, 6, 8, 10)));
2753         assertAppStateDurations(createDurations(1, 5), testObj.add(
2754                 createDurations(1, 2, 3, 4), createDurations(2, 3, 4, 5)));
2755         assertAppStateDurations(createDurations(1, 4, 6, 9), testObj.add(
2756                 createDurations(2, 4, 6, 9), createDurations(1, 4, 7, 8)));
2757         assertAppStateDurations(createDurations(1, 4, 5, 8, 9, 10), testObj.add(
2758                 createDurations(1, 4, 6, 8), createDurations(1, 3, 5, 8, 9, 10)));
2759     }
2760 
2761     @Test
2762     public void testSubtractAppStateDurations() throws Exception {
2763         final BaseAppStateDurations testObj = new BaseAppStateDurations(0, "", 1, "", null) {};
2764         assertAppStateDurations(null, testObj.subtract(null, null));
2765         assertAppStateDurations(null, testObj.subtract(null, new LinkedList<BaseTimeEvent>()));
2766         assertAppStateDurations(new LinkedList<BaseTimeEvent>(), testObj.subtract(
2767                 new LinkedList<BaseTimeEvent>(), null));
2768         assertAppStateDurations(createDurations(1), testObj.subtract(
2769                 createDurations(1), new LinkedList<BaseTimeEvent>()));
2770         assertAppStateDurations(new LinkedList<BaseTimeEvent>(), testObj.subtract(
2771                 new LinkedList<BaseTimeEvent>(), createDurations(1)));
2772         assertAppStateDurations(new LinkedList<BaseTimeEvent>(), testObj.subtract(
2773                 createDurations(1), createDurations(1)));
2774         assertAppStateDurations(createDurations(1, 2, 5, 6, 9, 10), testObj.subtract(
2775                 createDurations(1, 3, 5, 7, 9), createDurations(2, 4, 6, 8, 10)));
2776         assertAppStateDurations(createDurations(1, 2, 3, 4), testObj.subtract(
2777                 createDurations(1, 4, 6, 7, 9, 10), createDurations(2, 3, 5, 8, 9, 10)));
2778         assertAppStateDurations(createDurations(3, 4, 9, 10), testObj.subtract(
2779                 createDurations(1, 4, 6, 8, 9, 10), createDurations(1, 3, 5, 8)));
2780         assertAppStateDurations(createDurations(1, 2, 3, 4, 5, 6, 7, 8), testObj.subtract(
2781                 createDurations(1, 6, 7, 8), createDurations(2, 3, 4, 5, 8, 10)));
2782         assertAppStateDurations(createDurations(5, 6), testObj.subtract(
2783                 createDurations(2, 3, 5, 6), createDurations(1, 4, 7, 8)));
2784         assertAppStateDurations(createDurations(2, 3, 4, 5, 6, 7, 8), testObj.subtract(
2785                 createDurations(1), createDurations(1, 2, 3, 4, 5, 6, 7, 8)));
2786     }
2787 
2788     private void assertAppStateDurations(LinkedList<BaseTimeEvent> expected,
2789             LinkedList<BaseTimeEvent> actual) throws Exception {
2790         assertListEquals(expected, actual);
2791     }
2792 
2793     private <T> void assertListEquals(LinkedList<T> expected, LinkedList<T> actual) {
2794         assertEquals(expected == null || expected.isEmpty(), actual == null || actual.isEmpty());
2795         if (expected != null) {
2796             if (expected.size() > 0) {
2797                 assertEquals(expected.size(), actual.size());
2798             }
2799             while (expected.peek() != null) {
2800                 assertTrue(expected.poll().equals(actual.poll()));
2801             }
2802         }
2803     }
2804 
createDurations(long... timestamps)2805     private LinkedList<BaseTimeEvent> createDurations(long... timestamps) {
2806         return Arrays.stream(timestamps).mapToObj(BaseTimeEvent::new)
2807                 .collect(LinkedList<BaseTimeEvent>::new, LinkedList<BaseTimeEvent>::add,
2808                 (a, b) -> a.addAll(b));
2809     }
2810 
createIntLinkedList(int[] vals)2811     private LinkedList<Integer> createIntLinkedList(int[] vals) {
2812         return Arrays.stream(vals).collect(LinkedList<Integer>::new, LinkedList<Integer>::add,
2813                 (a, b) -> a.addAll(b));
2814     }
2815 
2816     @Test
testAppStateTimeSlotEvents()2817     public void testAppStateTimeSlotEvents() throws Exception {
2818         final long maxTrackingDuration = 5_000L;
2819         assertAppStateTimeSlotEvents(new int[] {2, 2, 0, 0, 1},
2820                 new long[] {1_500, 1_500, 2_100, 2_999, 5_999}, 5_000);
2821         assertAppStateTimeSlotEvents(new int[] {2, 2, 0, 0, 1, 1},
2822                 new long[] {1_500, 1_500, 2_100, 2_999, 5_999, 6_000}, 6_000);
2823         assertAppStateTimeSlotEvents(new int[] {2, 0, 0, 1, 1, 1},
2824                 new long[] {1_500, 1_500, 2_100, 2_999, 5_999, 6_000, 7_000}, 7_000);
2825         assertMergeAppStateTimeSlotEvents(new int[] {}, new long[] {}, new long[] {}, 0);
2826         assertMergeAppStateTimeSlotEvents(new int[] {1}, new long[] {}, new long[] {1_500}, 1_000);
2827         assertMergeAppStateTimeSlotEvents(new int[] {1}, new long[] {1_500}, new long[] {}, 1_000);
2828         assertMergeAppStateTimeSlotEvents(new int[] {1, 1},
2829                 new long[] {1_500}, new long[] {2_500}, 2_000);
2830         assertMergeAppStateTimeSlotEvents(new int[] {1, 1},
2831                 new long[] {2_500}, new long[] {1_500}, 2_000);
2832         assertMergeAppStateTimeSlotEvents(new int[] {1, 2, 1},
2833                 new long[] {1_500, 2_500}, new long[] {2_600, 3_000}, 3_000);
2834         assertMergeAppStateTimeSlotEvents(new int[] {2, 1, 1},
2835                 new long[] {2_600, 3_500}, new long[] {1_500, 1_600}, 3_000);
2836         assertMergeAppStateTimeSlotEvents(new int[] {1, 2, 1},
2837                 new long[] {1_500, 3_500}, new long[] {2_600, 2_700}, 3_000);
2838         assertMergeAppStateTimeSlotEvents(new int[] {1, 2, 1},
2839                 new long[] {2_500, 2_600}, new long[] {1_500, 3_700}, 3_000);
2840         assertMergeAppStateTimeSlotEvents(new int[] {1, 0, 0, 0, 0, 1},
2841                 new long[] {2_500, 8_600}, new long[] {1_500, 3_700}, 8_000);
2842     }
2843 
createBaseAppStateTimeSlotEvents( long slotSize, long maxTrackingDuration, long[] timestamps)2844     private BaseAppStateTimeSlotEvents createBaseAppStateTimeSlotEvents(
2845             long slotSize, long maxTrackingDuration, long[] timestamps) {
2846         final BaseAppStateTimeSlotEvents testObj = new BaseAppStateTimeSlotEvents(
2847                 0, "", 1, slotSize, "", () -> maxTrackingDuration) {};
2848         for (int i = 0; i < timestamps.length; i++) {
2849             testObj.addEvent(timestamps[i], 0);
2850         }
2851         return testObj;
2852     }
2853 
assertAppStateTimeSlotEvents(int[] expectedEvents, long[] timestamps, long expectedCurTimeslot)2854     private void assertAppStateTimeSlotEvents(int[] expectedEvents, long[] timestamps,
2855             long expectedCurTimeslot) {
2856         final BaseAppStateTimeSlotEvents testObj = createBaseAppStateTimeSlotEvents(1_000L,
2857                 5_000L, timestamps);
2858         assertEquals(expectedCurTimeslot, testObj.getCurrentSlotStartTime(0));
2859         assertListEquals(createIntLinkedList(expectedEvents), testObj.getRawEvents(0));
2860     }
2861 
assertMergeAppStateTimeSlotEvents(int[] expectedEvents, long[] timestamps1, long[] timestamps2, long expectedCurTimeslot)2862     private void assertMergeAppStateTimeSlotEvents(int[] expectedEvents, long[] timestamps1,
2863             long[] timestamps2, long expectedCurTimeslot) {
2864         final BaseAppStateTimeSlotEvents testObj1 = createBaseAppStateTimeSlotEvents(1_000L,
2865                 5_000L, timestamps1);
2866         final BaseAppStateTimeSlotEvents testObj2 = createBaseAppStateTimeSlotEvents(1_000L,
2867                 5_000L, timestamps2);
2868         testObj1.add(testObj2);
2869         assertEquals(expectedCurTimeslot, testObj1.getCurrentSlotStartTime(0));
2870         assertListEquals(createIntLinkedList(expectedEvents), testObj1.getRawEvents(0));
2871     }
2872 
2873     @Test
testMergeUidBatteryUsage()2874     public void testMergeUidBatteryUsage() throws Exception {
2875         final UidBatteryStates testObj = new UidBatteryStates(0, "", null);
2876         assertListEquals(null, testObj.add(null, null));
2877         assertListEquals(new LinkedList<UidStateEventWithBattery>(), testObj.add(
2878                 null, new LinkedList<UidStateEventWithBattery>()));
2879         assertListEquals(new LinkedList<UidStateEventWithBattery>(), testObj.add(
2880                 new LinkedList<UidStateEventWithBattery>(), null));
2881         assertListEquals(createUidStateEventWithBatteryList(
2882                 new boolean[] {true}, new long[] {10L}, new double[] {10.0d}),
2883                 testObj.add(createUidStateEventWithBatteryList(
2884                 new boolean[] {true}, new long[] {10L}, new double[] {10.0d}),
2885                 new LinkedList<UidStateEventWithBattery>()));
2886         assertListEquals(createUidStateEventWithBatteryList(
2887                 new boolean[] {true}, new long[] {10L}, new double[] {10.0d}),
2888                 testObj.add(new LinkedList<UidStateEventWithBattery>(),
2889                 createUidStateEventWithBatteryList(
2890                 new boolean[] {true}, new long[] {10L}, new double[] {10.0d})));
2891         assertListEquals(createUidStateEventWithBatteryList(
2892                 new boolean[] {true}, new long[] {10L}, new double[] {10.0d}),
2893                 testObj.add(createUidStateEventWithBatteryList(
2894                 new boolean[] {true}, new long[] {11L}, new double[] {11.0d}),
2895                 createUidStateEventWithBatteryList(
2896                 new boolean[] {true}, new long[] {10L}, new double[] {10.0d})));
2897         assertListEquals(createUidStateEventWithBatteryList(
2898                 new boolean[] {true}, new long[] {10L}, new double[] {10.0d}),
2899                 testObj.add(createUidStateEventWithBatteryList(
2900                 new boolean[] {true, false}, new long[] {11L, 12L}, new double[] {11.0d, 1.0d}),
2901                 createUidStateEventWithBatteryList(
2902                 new boolean[] {true}, new long[] {10L}, new double[] {10.0d})));
2903         assertListEquals(createUidStateEventWithBatteryList(
2904                 new boolean[] {true}, new long[] {10L}, new double[] {10.0d}),
2905                 testObj.add(createUidStateEventWithBatteryList(
2906                 new boolean[] {true, false, true}, new long[] {11L, 12L, 13L},
2907                 new double[] {11.0d, 1.0d, 13.0d}),
2908                 createUidStateEventWithBatteryList(
2909                 new boolean[] {true}, new long[] {10L}, new double[] {10.0d})));
2910         assertListEquals(createUidStateEventWithBatteryList(
2911                 new boolean[] {true, false}, new long[] {10L, 13L}, new double[] {10.0d, 3.0d}),
2912                 testObj.add(createUidStateEventWithBatteryList(
2913                 new boolean[] {true, false}, new long[] {11L, 13L}, new double[] {11.0d, 2.0d}),
2914                 createUidStateEventWithBatteryList(
2915                 new boolean[] {true, false}, new long[] {10L, 12L}, new double[] {10.0d, 2.0d})));
2916         assertListEquals(createUidStateEventWithBatteryList(
2917                 new boolean[] {true, false, true}, new long[] {10L, 13L, 14L},
2918                 new double[] {10.0d, 3.0d, 14.0d}),
2919                 testObj.add(createUidStateEventWithBatteryList(
2920                 new boolean[] {true, false, true}, new long[] {11L, 13L, 14L},
2921                 new double[] {11.0d, 2.0d, 14.0d}),
2922                 createUidStateEventWithBatteryList(
2923                 new boolean[] {true, false}, new long[] {10L, 12L}, new double[] {10.0d, 2.0d})));
2924         assertListEquals(createUidStateEventWithBatteryList(
2925                 new boolean[] {true, false, true, false, true, false},
2926                 new long[] {10L, 13L, 14L, 17L, 18L, 21L},
2927                 new double[] {10.0d, 3.0d, 14.0d, 3.0d, 18.0d, 3.0d}),
2928                 testObj.add(createUidStateEventWithBatteryList(
2929                 new boolean[] {true, false, true, false, true, false},
2930                 new long[] {11L, 13L, 15L, 17L, 19L, 21L},
2931                 new double[] {11.0d, 2.0d, 15.0d, 2.0d, 19.0d, 2.0d}),
2932                 createUidStateEventWithBatteryList(
2933                 new boolean[] {true, false, true, false, true, false},
2934                 new long[] {10L, 12L, 14L, 16L, 18L, 20L},
2935                 new double[] {10.0d, 2.0d, 14.0d, 2.0d, 18.0d, 2.0d})));
2936         assertListEquals(createUidStateEventWithBatteryList(
2937                 new boolean[] {true, false, true, false, true, false, true, false, true, false},
2938                 new long[] {10L, 11L, 12L, 13L, 14L, 15L, 16L, 17L, 18L, 19L},
2939                 new double[] {10.0d, 1.0d, 12.0d, 1.0d, 14.0d, 1.0d, 16.0d, 1.0d, 18.0d, 1.0d}),
2940                 testObj.add(createUidStateEventWithBatteryList(
2941                 new boolean[] {true, false, true, false},
2942                 new long[] {12L, 13L, 16L, 17L},
2943                 new double[] {12.0d, 1.0d, 16.0d, 1.0d}),
2944                 createUidStateEventWithBatteryList(
2945                 new boolean[] {true, false, true, false, true, false},
2946                 new long[] {10L, 11L, 14L, 15L, 18L, 19L},
2947                 new double[] {10.0d, 1.0d, 14.0d, 1.0d, 18.0d, 1.0d})));
2948         assertListEquals(createUidStateEventWithBatteryList(
2949                 new boolean[] {true, false, true, false},
2950                 new long[] {10L, 14L, 18L, 19L},
2951                 new double[] {10.0d, 4.0d, 18.0d, 1.0d}),
2952                 testObj.add(createUidStateEventWithBatteryList(
2953                 new boolean[] {true, false, true, false},
2954                 new long[] {11L, 12L, 13L, 14L},
2955                 new double[] {11.0d, 1.0d, 13.0d, 1.0d}),
2956                 createUidStateEventWithBatteryList(
2957                 new boolean[] {true, false, true, false, true, false},
2958                 new long[] {10L, 11L, 12L, 13L, 18L, 19L},
2959                 new double[] {10.0d, 1.0d, 12.0d, 1.0d, 18.0d, 1.0d})));
2960         assertListEquals(createUidStateEventWithBatteryList(
2961                 new boolean[] {true, false, true, false},
2962                 new long[] {10L, 14L, 18L, 19L},
2963                 new double[] {10.0d, 4.0d, 18.0d, 1.0d}),
2964                 testObj.add(createUidStateEventWithBatteryList(
2965                 new boolean[] {true, false, true, false},
2966                 new long[] {10L, 14L, 18L, 19L},
2967                 new double[] {10.0d, 4.0d, 18.0d, 1.0d}),
2968                 createUidStateEventWithBatteryList(
2969                 new boolean[] {true, false, true, false, true, false},
2970                 new long[] {10L, 11L, 12L, 13L, 18L, 19L},
2971                 new double[] {10.0d, 1.0d, 12.0d, 1.0d, 18.0d, 1.0d})));
2972     }
2973 
2974     @SuppressWarnings("GuardedBy")
2975     @Test
testPersistRestrictionSettings()2976     public void testPersistRestrictionSettings() throws Exception {
2977         final RestrictionSettings settings = mBgRestrictionController.mRestrictionSettings;
2978         final String testPkg0 = TEST_PACKAGE_BASE + 0;
2979         final String testPkg1 = TEST_PACKAGE_BASE + 1;
2980         final String testPkg2 = TEST_PACKAGE_BASE + 2;
2981         final String testPkg3 = TEST_PACKAGE_BASE + 3;
2982         final int testUid0 = UserHandle.getUid(TEST_USER0, TEST_PACKAGE_APPID_BASE + 0);
2983         final int testUid1 = UserHandle.getUid(TEST_USER0, TEST_PACKAGE_APPID_BASE + 1);
2984         final int testUid2 = UserHandle.getUid(TEST_USER1, TEST_PACKAGE_APPID_BASE + 2);
2985         final int testUid3 = UserHandle.getUid(TEST_USER1, TEST_PACKAGE_APPID_BASE + 3);
2986         settings.reset();
2987         setRestrictionSettings(settings, testPkg0, testUid0,
2988                 RESTRICTION_LEVEL_ADAPTIVE_BUCKET,
2989                 10_000L, REASON_MAIN_DEFAULT | REASON_SUB_DEFAULT_UNDEFINED,
2990                 new long[] {0L, 0L}, false);
2991         setRestrictionSettings(settings, testPkg1, testUid1,
2992                 RESTRICTION_LEVEL_RESTRICTED_BUCKET,
2993                 20_000L, REASON_MAIN_FORCED_BY_SYSTEM | REASON_SUB_FORCED_SYSTEM_FLAG_ABUSE,
2994                 new long[] {10_000L, 0L}, false);
2995         setRestrictionSettings(settings, testPkg2, testUid2,
2996                 RESTRICTION_LEVEL_BACKGROUND_RESTRICTED,
2997                 25_000L, REASON_MAIN_FORCED_BY_USER | REASON_SUB_FORCED_USER_FLAG_INTERACTION,
2998                 new long[] {0L, 15_000L}, false);
2999         setRestrictionSettings(settings, testPkg3, testUid3,
3000                 RESTRICTION_LEVEL_RESTRICTED_BUCKET,
3001                 30_000L, REASON_MAIN_DEFAULT | REASON_SUB_DEFAULT_UNDEFINED,
3002                 new long[] {0L, 0L}, false);
3003         RestrictionSettings test = (RestrictionSettings) settings.clone();
3004 
3005         // Verify our clone works correctly.
3006         assertTrue(settings.equals(test));
3007 
3008         // Reset the test object.
3009         test.resetToDefault();
3010 
3011         // Save the original data into xml.
3012         settings.persistToXml(TEST_USER0);
3013         settings.persistToXml(TEST_USER1);
3014 
3015         // Load it to our test object.
3016         test.loadFromXml(false);
3017         // Verify we restored it correctly.
3018         assertTrue(settings.equals(test));
3019 
3020         // Remove one package.
3021         settings.removePackage(testPkg3, testUid3);
3022         // Verify it.
3023         verifyLoadedSettings(settings);
3024 
3025         // Add it back.
3026         setRestrictionSettings(settings, testPkg3, testUid3,
3027                 RESTRICTION_LEVEL_RESTRICTED_BUCKET,
3028                 30_000L, REASON_MAIN_DEFAULT | REASON_SUB_DEFAULT_UNDEFINED,
3029                 new long[] {0L, 1_000L}, true);
3030         // Verify it.
3031         verifyLoadedSettings(settings);
3032 
3033         // Remove one user.
3034         settings.removeUser(TEST_USER1);
3035         // Verify it.
3036         verifyLoadedSettings(settings);
3037     }
3038 
3039     @Test
testCarrierPrivilegedAppListener()3040     public void testCarrierPrivilegedAppListener() throws Exception {
3041         final long shortMs = 1_000L;
3042         for (int i = 0; i < MOCK_PRIVILEGED_PACKAGES.length; i++) {
3043             verifyPotentialSystemExemptionReason(REASON_CARRIER_PRIVILEGED_APP,
3044                     MOCK_PRIVILEGED_PACKAGES[i],
3045                     MOCK_PRIVILEGED_UIDS[i]);
3046         }
3047         verifyPotentialSystemExemptionReason(REASON_DENIED,
3048                 MOCK_PRIVILEGED_PACKAGES_2,
3049                 MOCK_PRIVILEGED_UIDS_2);
3050 
3051         mPhoneCarrierPrivileges.addNewPrivilegePackages(0,
3052                 MOCK_PRIVILEGED_PACKAGES_2,
3053                 MOCK_PRIVILEGED_UIDS_2);
3054         Thread.sleep(shortMs);
3055 
3056         verifyPotentialSystemExemptionReason(REASON_CARRIER_PRIVILEGED_APP,
3057                 MOCK_PRIVILEGED_PACKAGES_2,
3058                 MOCK_PRIVILEGED_UIDS_2);
3059 
3060         verifyPotentialSystemExemptionReason(REASON_DENIED,
3061                 MOCK_PRIVILEGED_PACKAGES_0,
3062                 MOCK_PRIVILEGED_UIDS_0);
3063 
3064         verifyPotentialSystemExemptionReason(REASON_CARRIER_PRIVILEGED_APP,
3065                 MOCK_PRIVILEGED_PACKAGES_1,
3066                 MOCK_PRIVILEGED_UIDS_1);
3067 
3068         mPhoneCarrierPrivileges.addNewPrivilegePackages(1,
3069                 new String[0], new int[0]);
3070         Thread.sleep(shortMs);
3071 
3072         verifyPotentialSystemExemptionReason(REASON_CARRIER_PRIVILEGED_APP,
3073                 MOCK_PRIVILEGED_PACKAGES_2,
3074                 MOCK_PRIVILEGED_UIDS_2);
3075 
3076         verifyPotentialSystemExemptionReason(REASON_DENIED,
3077                 MOCK_PRIVILEGED_PACKAGES_0,
3078                 MOCK_PRIVILEGED_UIDS_0);
3079 
3080         verifyPotentialSystemExemptionReason(REASON_DENIED,
3081                 MOCK_PRIVILEGED_PACKAGES_1,
3082                 MOCK_PRIVILEGED_UIDS_1);
3083 
3084         mPhoneCarrierPrivileges.addNewPrivilegePackages(0,
3085                 MOCK_PRIVILEGED_PACKAGES_0,
3086                 MOCK_PRIVILEGED_UIDS_0);
3087         Thread.sleep(shortMs);
3088 
3089         verifyPotentialSystemExemptionReason(REASON_DENIED,
3090                 MOCK_PRIVILEGED_PACKAGES_2,
3091                 MOCK_PRIVILEGED_UIDS_2);
3092 
3093         verifyPotentialSystemExemptionReason(REASON_CARRIER_PRIVILEGED_APP,
3094                 MOCK_PRIVILEGED_PACKAGES_0,
3095                 MOCK_PRIVILEGED_UIDS_0);
3096 
3097         verifyPotentialSystemExemptionReason(REASON_DENIED,
3098                 MOCK_PRIVILEGED_PACKAGES_1,
3099                 MOCK_PRIVILEGED_UIDS_1);
3100     }
3101 
verifyPotentialSystemExemptionReason(int expectedReason, String[] packages, int[] uids)3102     private void verifyPotentialSystemExemptionReason(int expectedReason,
3103             String[] packages, int[] uids) throws Exception {
3104         for (int i = 0; i < packages.length; i++) {
3105             assertEquals(expectedReason,
3106                     mBgRestrictionController.getPotentialSystemExemptionReason(
3107                             uids[i], packages[i]));
3108         }
3109     }
3110 
verifyLoadedSettings(RestrictionSettings settings)3111     private void verifyLoadedSettings(RestrictionSettings settings) throws Exception {
3112         // Make a new copy and reset it.
3113         RestrictionSettings test = (RestrictionSettings) settings.clone();
3114         test.resetToDefault();
3115 
3116         // Wait for the idleness so the data is persisted.
3117         waitForIdleHandler(mBgRestrictionController.getBackgroundHandler());
3118         // Load it to our test object.
3119         test.loadFromXml(false);
3120         // Verify we restored it correctly.
3121         assertTrue(settings.equals(test));
3122     }
3123 
3124     @SuppressWarnings("GuardedBy")
setRestrictionSettings(RestrictionSettings settings, String pkgName, int uid, int level, long levelTs, int reason, long[] notificationTime, boolean persist)3125     private void setRestrictionSettings(RestrictionSettings settings, String pkgName, int uid,
3126             int level, long levelTs, int reason, long[] notificationTime, boolean persist) {
3127         mCurrentTimeMillis = levelTs;
3128         settings.update(pkgName, uid, level, reason & REASON_MAIN_MASK, reason & REASON_SUB_MASK);
3129         final RestrictionSettings.PkgSettings pkgSettings = settings.getRestrictionSettingsLocked(
3130                 uid, pkgName);
3131         for (int i = 0; i < notificationTime.length; i++) {
3132             pkgSettings.setLastNotificationTime(i, notificationTime[i], persist);
3133         }
3134     }
3135 
createUidStateEventWithBatteryList( boolean[] isStart, long[] timestamps, double[] batteryUsage)3136     private LinkedList<UidStateEventWithBattery> createUidStateEventWithBatteryList(
3137             boolean[] isStart, long[] timestamps, double[] batteryUsage) {
3138         final LinkedList<UidStateEventWithBattery> result = new LinkedList<>();
3139         for (int i = 0; i < isStart.length; i++) {
3140             result.add(new UidStateEventWithBattery(isStart[i], timestamps[i],
3141                         new ImmutableBatteryUsage(0.0d, 0.0d, batteryUsage[i], 0.0d, 0.0d), null));
3142         }
3143         return result;
3144     }
3145 
3146     private class PhoneCarrierPrivileges {
3147         private final SparseArray<Pair<String[], int[]>> mPackages = new SparseArray<>();
3148         private final SparseArray<Pair<Executor, CarrierPrivilegesCallback>> mListeners =
3149                 new SparseArray<>();
3150 
PhoneCarrierPrivileges(TelephonyManager telephonyManager, int phoneIds)3151         PhoneCarrierPrivileges(TelephonyManager telephonyManager, int phoneIds) {
3152             doReturn(phoneIds).when(telephonyManager).getActiveModemCount();
3153             doAnswer(inv -> {
3154                 registerCarrierPrivilegesCallback(
3155                         inv.getArgument(0),
3156                         inv.getArgument(1),
3157                         inv.getArgument(2));
3158                 return null;
3159             }).when(telephonyManager).registerCarrierPrivilegesCallback(
3160                     anyInt(), anyObject(), anyObject());
3161         }
3162 
registerCarrierPrivilegesCallback(int phoneId, Executor executor, CarrierPrivilegesCallback callback)3163         public void registerCarrierPrivilegesCallback(int phoneId, Executor executor,
3164                 CarrierPrivilegesCallback callback) {
3165             mListeners.put(phoneId, Pair.create(executor, callback));
3166             final Pair<String[], int[]> pkgs = mPackages.get(phoneId);
3167             final Set<String> pkgNames = pkgs != null
3168                     ? Arrays.stream(pkgs.first).collect(Collectors.toUnmodifiableSet())
3169                     : Collections.emptySet();
3170             final Set<Integer> uids = pkgs != null
3171                     ? Arrays.stream(pkgs.second).boxed().collect(Collectors.toUnmodifiableSet())
3172                     : Collections.emptySet();
3173             executor.execute(() -> callback.onCarrierPrivilegesChanged(pkgNames, uids));
3174         }
3175 
addNewPrivilegePackages(int phoneId, String[] pkgNames, int[] uids)3176         public void addNewPrivilegePackages(int phoneId, String[] pkgNames, int[] uids) {
3177             mPackages.put(phoneId, Pair.create(pkgNames, uids));
3178             final Pair<Executor, CarrierPrivilegesCallback> callback = mListeners.get(phoneId);
3179             if (callback != null) {
3180                 callback.first.execute(() -> callback.second.onCarrierPrivilegesChanged(
3181                         Arrays.stream(pkgNames).collect(Collectors.toUnmodifiableSet()),
3182                         Arrays.stream(uids).boxed().collect(Collectors.toUnmodifiableSet())));
3183             }
3184         }
3185     }
3186 
3187     private class TestBgRestrictionInjector extends AppRestrictionController.Injector {
3188         private Context mContext;
3189 
TestBgRestrictionInjector(Context context)3190         TestBgRestrictionInjector(Context context) {
3191             super(context);
3192             mContext = context;
3193         }
3194 
3195         @Override
initAppStateTrackers(AppRestrictionController controller)3196         void initAppStateTrackers(AppRestrictionController controller) {
3197             try {
3198                 mAppBatteryTracker = new AppBatteryTracker(mContext, controller,
3199                         TestAppBatteryTrackerInjector.class.getDeclaredConstructor(
3200                                 BackgroundRestrictionTest.class),
3201                         BackgroundRestrictionTest.this);
3202                 controller.addAppStateTracker(mAppBatteryTracker);
3203                 mAppBatteryExemptionTracker = new AppBatteryExemptionTracker(mContext, controller,
3204                         TestAppBatteryExemptionTrackerInjector.class.getDeclaredConstructor(
3205                                 BackgroundRestrictionTest.class),
3206                         BackgroundRestrictionTest.this);
3207                 controller.addAppStateTracker(mAppBatteryExemptionTracker);
3208                 mAppFGSTracker = new AppFGSTracker(mContext, controller,
3209                         TestAppFGSTrackerInjector.class.getDeclaredConstructor(
3210                                 BackgroundRestrictionTest.class),
3211                         BackgroundRestrictionTest.this);
3212                 controller.addAppStateTracker(mAppFGSTracker);
3213                 mAppMediaSessionTracker = new AppMediaSessionTracker(mContext, controller,
3214                         TestAppMediaSessionTrackerInjector.class.getDeclaredConstructor(
3215                                 BackgroundRestrictionTest.class),
3216                         BackgroundRestrictionTest.this);
3217                 controller.addAppStateTracker(mAppMediaSessionTracker);
3218                 mAppBroadcastEventsTracker = new AppBroadcastEventsTracker(mContext, controller,
3219                         TestAppBroadcastEventsTrackerInjector.class.getDeclaredConstructor(
3220                                 BackgroundRestrictionTest.class),
3221                         BackgroundRestrictionTest.this);
3222                 controller.addAppStateTracker(mAppBroadcastEventsTracker);
3223                 mAppBindServiceEventsTracker = new AppBindServiceEventsTracker(mContext, controller,
3224                         TestAppBindServiceEventsTrackerInjector.class.getDeclaredConstructor(
3225                                 BackgroundRestrictionTest.class),
3226                         BackgroundRestrictionTest.this);
3227                 controller.addAppStateTracker(mAppBindServiceEventsTracker);
3228                 mAppPermissionTracker = new AppPermissionTracker(mContext, controller,
3229                         TestAppPermissionTrackerInjector.class.getDeclaredConstructor(
3230                                 BackgroundRestrictionTest.class),
3231                         BackgroundRestrictionTest.this);
3232                 controller.addAppStateTracker(mAppPermissionTracker);
3233             } catch (NoSuchMethodException e) {
3234                 // Won't happen.
3235             }
3236         }
3237 
3238         @Override
getActivityManagerInternal()3239         ActivityManagerInternal getActivityManagerInternal() {
3240             return mActivityManagerInternal;
3241         }
3242 
3243         @Override
getAppRestrictionController()3244         AppRestrictionController getAppRestrictionController() {
3245             return mBgRestrictionController;
3246         }
3247 
3248         @Override
getAppOpsManager()3249         AppOpsManager getAppOpsManager() {
3250             return mAppOpsManager;
3251         }
3252 
3253         @Override
getAppStandbyInternal()3254         AppStandbyInternal getAppStandbyInternal() {
3255             return mAppStandbyInternal;
3256         }
3257 
3258         @Override
getAppHibernationInternal()3259         AppHibernationManagerInternal getAppHibernationInternal() {
3260             return mAppHibernationInternal;
3261         }
3262 
3263         @Override
getAppStateTracker()3264         AppStateTracker getAppStateTracker() {
3265             return mAppStateTracker;
3266         }
3267 
3268         @Override
getIActivityManager()3269         IActivityManager getIActivityManager() {
3270             return mIActivityManager;
3271         }
3272 
3273         @Override
getUserManagerInternal()3274         UserManagerInternal getUserManagerInternal() {
3275             return mUserManagerInternal;
3276         }
3277 
3278         @Override
getPackageManagerInternal()3279         PackageManagerInternal getPackageManagerInternal() {
3280             return mPackageManagerInternal;
3281         }
3282 
3283         @Override
getPackageManager()3284         PackageManager getPackageManager() {
3285             return mPackageManager;
3286         }
3287 
3288         @Override
getNotificationManager()3289         NotificationManager getNotificationManager() {
3290             return mNotificationManager;
3291         }
3292 
3293         @Override
getRoleManager()3294         RoleManager getRoleManager() {
3295             return mRoleManager;
3296         }
3297 
3298         @Override
getTelephonyManager()3299         TelephonyManager getTelephonyManager() {
3300             return mTelephonyManager;
3301         }
3302 
3303         @Override
getAppFGSTracker()3304         AppFGSTracker getAppFGSTracker() {
3305             return mAppFGSTracker;
3306         }
3307 
3308         @Override
getAppMediaSessionTracker()3309         AppMediaSessionTracker getAppMediaSessionTracker() {
3310             return mAppMediaSessionTracker;
3311         }
3312 
3313         @Override
getActivityManagerService()3314         ActivityManagerService getActivityManagerService() {
3315             return mActivityManagerService;
3316         }
3317 
3318         @Override
getUidBatteryUsageProvider()3319         UidBatteryUsageProvider getUidBatteryUsageProvider() {
3320             return mAppBatteryTracker;
3321         }
3322 
3323         @Override
getAppBatteryExemptionTracker()3324         AppBatteryExemptionTracker getAppBatteryExemptionTracker() {
3325             return mAppBatteryExemptionTracker;
3326         }
3327 
3328         @Override
getAppPermissionTracker()3329         AppPermissionTracker getAppPermissionTracker() {
3330             return mAppPermissionTracker;
3331         }
3332 
3333         @Override
scheduleInitTrackers(Handler handler, Runnable initializers)3334         void scheduleInitTrackers(Handler handler, Runnable initializers) {
3335             initializers.run();
3336         }
3337 
3338         @Override
getDataSystemDeDirectory(@serIdInt int userId)3339         File getDataSystemDeDirectory(@UserIdInt int userId) {
3340             return new File(mContext.getFilesDir(), Integer.toString(userId));
3341         }
3342 
3343         @Override
currentTimeMillis()3344         long currentTimeMillis() {
3345             return mCurrentTimeMillis;
3346         }
3347 
3348         @Override
isTest()3349         boolean isTest() {
3350             return true;
3351         }
3352     }
3353 
3354     private class TestBaseTrackerInjector<T extends BaseAppStatePolicy>
3355             extends BaseAppStateTracker.Injector<T> {
3356         @Override
onSystemReady()3357         void onSystemReady() {
3358             getPolicy().onSystemReady();
3359         }
3360 
3361         @Override
getActivityManagerInternal()3362         ActivityManagerInternal getActivityManagerInternal() {
3363             return BackgroundRestrictionTest.this.mActivityManagerInternal;
3364         }
3365 
3366         @Override
getBatteryManagerInternal()3367         BatteryManagerInternal getBatteryManagerInternal() {
3368             return BackgroundRestrictionTest.this.mBatteryManagerInternal;
3369         }
3370 
3371         @Override
getBatteryStatsInternal()3372         BatteryStatsInternal getBatteryStatsInternal() {
3373             return BackgroundRestrictionTest.this.mBatteryStatsInternal;
3374         }
3375 
3376         @Override
getDeviceIdleInternal()3377         DeviceIdleInternal getDeviceIdleInternal() {
3378             return BackgroundRestrictionTest.this.mDeviceIdleInternal;
3379         }
3380 
3381         @Override
getUserManagerInternal()3382         UserManagerInternal getUserManagerInternal() {
3383             return BackgroundRestrictionTest.this.mUserManagerInternal;
3384         }
3385 
3386         @Override
currentTimeMillis()3387         long currentTimeMillis() {
3388             return BackgroundRestrictionTest.this.mCurrentTimeMillis;
3389         }
3390 
3391         @Override
getPackageManager()3392         PackageManager getPackageManager() {
3393             return BackgroundRestrictionTest.this.mPackageManager;
3394         }
3395 
3396         @Override
getPermissionManagerServiceInternal()3397         PermissionManagerServiceInternal getPermissionManagerServiceInternal() {
3398             return BackgroundRestrictionTest.this.mPermissionManagerServiceInternal;
3399         }
3400 
3401         @Override
getAppOpsManager()3402         AppOpsManager getAppOpsManager() {
3403             return BackgroundRestrictionTest.this.mAppOpsManager;
3404         }
3405 
3406         @Override
getMediaSessionManager()3407         MediaSessionManager getMediaSessionManager() {
3408             return BackgroundRestrictionTest.this.mMediaSessionManager;
3409         }
3410 
3411         @Override
getNotificationManagerInternal()3412         NotificationManagerInternal getNotificationManagerInternal() {
3413             return BackgroundRestrictionTest.this.mNotificationManagerInternal;
3414         }
3415 
getPackageManagerInternal()3416         PackageManagerInternal getPackageManagerInternal() {
3417             return BackgroundRestrictionTest.this.mPackageManagerInternal;
3418         }
3419 
getPermissionManager()3420         PermissionManager getPermissionManager() {
3421             return BackgroundRestrictionTest.this.mPermissionManager;
3422         }
3423 
3424         @Override
getServiceStartForegroundTimeout()3425         long getServiceStartForegroundTimeout() {
3426             return 1_000; // ms
3427         }
3428 
3429         @Override
getRoleManager()3430         RoleManager getRoleManager() {
3431             return BackgroundRestrictionTest.this.mRoleManager;
3432         }
3433 
3434         @Override
getIAppOpsService()3435         IAppOpsService getIAppOpsService() {
3436             return BackgroundRestrictionTest.this.mIAppOpsService;
3437         }
3438     }
3439 
3440     private class TestAppBatteryTrackerInjector extends TestBaseTrackerInjector<AppBatteryPolicy> {
3441         @Override
setPolicy(AppBatteryPolicy policy)3442         void setPolicy(AppBatteryPolicy policy) {
3443             super.setPolicy(policy);
3444             BackgroundRestrictionTest.this.mAppBatteryPolicy = policy;
3445         }
3446     }
3447 
3448     private class TestAppBatteryExemptionTrackerInjector
3449             extends TestBaseTrackerInjector<AppBatteryExemptionPolicy> {
3450     }
3451 
3452     private class TestAppFGSTrackerInjector extends TestBaseTrackerInjector<AppFGSPolicy> {
3453     }
3454 
3455     private class TestAppMediaSessionTrackerInjector
3456             extends TestBaseTrackerInjector<AppMediaSessionPolicy> {
3457     }
3458 
3459     private class TestAppPermissionTrackerInjector
3460             extends TestBaseTrackerInjector<AppPermissionPolicy> {
3461     }
3462 
3463     private class TestAppBroadcastEventsTrackerInjector
3464             extends TestBaseTrackerInjector<AppBroadcastEventsPolicy> {
3465         @Override
setPolicy(AppBroadcastEventsPolicy policy)3466         void setPolicy(AppBroadcastEventsPolicy policy) {
3467             super.setPolicy(policy);
3468             policy.setTimeSlotSize(1_000L);
3469         }
3470     }
3471 
3472     private class TestAppBindServiceEventsTrackerInjector
3473             extends TestBaseTrackerInjector<AppBindServiceEventsPolicy> {
3474         @Override
setPolicy(AppBindServiceEventsPolicy policy)3475         void setPolicy(AppBindServiceEventsPolicy policy) {
3476             super.setPolicy(policy);
3477             policy.setTimeSlotSize(1_000L);
3478         }
3479     }
3480 }
3481