blob: 601999dde84bc24d44b7835439d51c3848f8e656 [file] [log] [blame]
Amith Yamasani17fffee2017-09-29 13:17:43 -07001/*
2 * Copyright (C) 2017 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
17package com.android.server.usage;
18
Amith Yamasani803eab692017-11-09 17:47:04 -080019import static android.app.usage.UsageEvents.Event.NOTIFICATION_SEEN;
Jason Monk1918ef72018-03-14 09:20:39 -040020import static android.app.usage.UsageEvents.Event.SLICE_PINNED;
21import static android.app.usage.UsageEvents.Event.SLICE_PINNED_PRIV;
Amith Yamasani7f53c7b2018-03-25 21:55:50 -070022import static android.app.usage.UsageEvents.Event.SYSTEM_INTERACTION;
Amith Yamasani803eab692017-11-09 17:47:04 -080023import static android.app.usage.UsageEvents.Event.USER_INTERACTION;
Amith Yamasani119be9a2018-02-18 22:23:00 -080024import static android.app.usage.UsageStatsManager.REASON_MAIN_DEFAULT;
25import static android.app.usage.UsageStatsManager.REASON_MAIN_FORCED;
26import static android.app.usage.UsageStatsManager.REASON_MAIN_PREDICTED;
27import static android.app.usage.UsageStatsManager.REASON_MAIN_TIMEOUT;
28import static android.app.usage.UsageStatsManager.REASON_MAIN_USAGE;
Amith Yamasaniafbccb72017-11-27 10:44:24 -080029import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_ACTIVE;
Amith Yamasani777b1532018-01-28 23:20:07 +000030import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_EXEMPTED;
Amith Yamasaniafbccb72017-11-27 10:44:24 -080031import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_FREQUENT;
Amith Yamasani93885192017-12-13 11:52:10 -080032import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_NEVER;
Amith Yamasaniafbccb72017-11-27 10:44:24 -080033import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RARE;
34import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_WORKING_SET;
Amith Yamasani803eab692017-11-09 17:47:04 -080035
Amith Yamasani17fffee2017-09-29 13:17:43 -070036import static org.junit.Assert.assertEquals;
37import static org.junit.Assert.assertFalse;
38import static org.junit.Assert.assertNotEquals;
39import static org.junit.Assert.assertTrue;
40
Sudheer Shanka101c3532018-01-08 16:28:42 -080041import static org.junit.Assert.fail;
Amith Yamasani777b1532018-01-28 23:20:07 +000042import static org.mockito.ArgumentMatchers.eq;
Amith Yamasani17fffee2017-09-29 13:17:43 -070043import static org.mockito.Matchers.anyInt;
44import static org.mockito.Matchers.anyString;
45import static org.mockito.Mockito.doReturn;
46import static org.mockito.Mockito.mock;
47
Amith Yamasani17fffee2017-09-29 13:17:43 -070048import android.app.usage.UsageEvents;
49import android.appwidget.AppWidgetManager;
50import android.content.Context;
51import android.content.ContextWrapper;
52import android.content.pm.ApplicationInfo;
53import android.content.pm.PackageInfo;
54import android.content.pm.PackageManager;
55import android.hardware.display.DisplayManager;
56import android.os.Handler;
57import android.os.Looper;
58import android.os.RemoteException;
Amith Yamasani53f06ea2018-01-05 17:53:46 -080059import android.platform.test.annotations.Presubmit;
60import android.support.test.filters.SmallTest;
Amith Yamasani17fffee2017-09-29 13:17:43 -070061import android.support.test.InstrumentationRegistry;
62import android.support.test.runner.AndroidJUnit4;
Sudheer Shanka101c3532018-01-08 16:28:42 -080063import android.util.ArraySet;
Amith Yamasani17fffee2017-09-29 13:17:43 -070064import android.view.Display;
65
66import com.android.server.SystemService;
67
68import org.junit.Before;
69import org.junit.Test;
70import org.junit.runner.RunWith;
71
72import java.io.File;
73import java.util.ArrayList;
Sudheer Shanka101c3532018-01-08 16:28:42 -080074import java.util.Arrays;
Amith Yamasani17fffee2017-09-29 13:17:43 -070075import java.util.List;
Sudheer Shanka101c3532018-01-08 16:28:42 -080076import java.util.Set;
Amith Yamasani17fffee2017-09-29 13:17:43 -070077
78/**
79 * Unit test for AppStandbyController.
80 */
81@RunWith(AndroidJUnit4.class)
Amith Yamasani53f06ea2018-01-05 17:53:46 -080082@Presubmit
83@SmallTest
Amith Yamasani17fffee2017-09-29 13:17:43 -070084public class AppStandbyControllerTests {
85
86 private static final String PACKAGE_1 = "com.example.foo";
87 private static final int UID_1 = 10000;
Amith Yamasani777b1532018-01-28 23:20:07 +000088 private static final String PACKAGE_EXEMPTED_1 = "com.android.exempted";
89 private static final int UID_EXEMPTED_1 = 10001;
Amith Yamasani17fffee2017-09-29 13:17:43 -070090 private static final int USER_ID = 0;
Sudheer Shanka101c3532018-01-08 16:28:42 -080091 private static final int USER_ID2 = 10;
92
93 private static final String ADMIN_PKG = "com.android.admin";
94 private static final String ADMIN_PKG2 = "com.android.admin2";
95 private static final String ADMIN_PKG3 = "com.android.admin3";
Amith Yamasani17fffee2017-09-29 13:17:43 -070096
97 private static final long MINUTE_MS = 60 * 1000;
98 private static final long HOUR_MS = 60 * MINUTE_MS;
99 private static final long DAY_MS = 24 * HOUR_MS;
100
Amith Yamasani301e94a2017-11-17 16:35:44 -0800101 private static final long WORKING_SET_THRESHOLD = 12 * HOUR_MS;
102 private static final long FREQUENT_THRESHOLD = 24 * HOUR_MS;
103 private static final long RARE_THRESHOLD = 48 * HOUR_MS;
104
Amith Yamasani17fffee2017-09-29 13:17:43 -0700105 private MyInjector mInjector;
Amith Yamasani93885192017-12-13 11:52:10 -0800106 private AppStandbyController mController;
Amith Yamasani17fffee2017-09-29 13:17:43 -0700107
108 static class MyContextWrapper extends ContextWrapper {
109 PackageManager mockPm = mock(PackageManager.class);
110
111 public MyContextWrapper(Context base) {
112 super(base);
113 }
114
115 public PackageManager getPackageManager() {
116 return mockPm;
117 }
118 }
119
120 static class MyInjector extends AppStandbyController.Injector {
121 long mElapsedRealtime;
122 boolean mIsCharging;
123 List<String> mPowerSaveWhitelistExceptIdle = new ArrayList<>();
124 boolean mDisplayOn;
125 DisplayManager.DisplayListener mDisplayListener;
Amith Yamasani777b1532018-01-28 23:20:07 +0000126 String mBoundWidgetPackage = PACKAGE_EXEMPTED_1;
Amith Yamasani17fffee2017-09-29 13:17:43 -0700127
128 MyInjector(Context context, Looper looper) {
129 super(context, looper);
130 }
131
132 @Override
133 void onBootPhase(int phase) {
134 }
135
136 @Override
137 int getBootPhase() {
138 return SystemService.PHASE_BOOT_COMPLETED;
139 }
140
141 @Override
142 long elapsedRealtime() {
143 return mElapsedRealtime;
144 }
145
146 @Override
147 long currentTimeMillis() {
148 return mElapsedRealtime;
149 }
150
151 @Override
152 boolean isAppIdleEnabled() {
153 return true;
154 }
155
156 @Override
157 boolean isCharging() {
158 return mIsCharging;
159 }
160
161 @Override
162 boolean isPowerSaveWhitelistExceptIdleApp(String packageName) throws RemoteException {
163 return mPowerSaveWhitelistExceptIdle.contains(packageName);
164 }
165
166 @Override
167 File getDataSystemDirectory() {
168 return new File(getContext().getFilesDir(), Long.toString(Math.randomLongInternal()));
169 }
170
171 @Override
172 void noteEvent(int event, String packageName, int uid) throws RemoteException {
173 }
174
175 @Override
176 boolean isPackageEphemeral(int userId, String packageName) {
177 // TODO: update when testing ephemeral apps scenario
178 return false;
179 }
180
181 @Override
182 int[] getRunningUserIds() {
183 return new int[] {USER_ID};
184 }
185
186 @Override
187 boolean isDefaultDisplayOn() {
188 return mDisplayOn;
189 }
190
191 @Override
192 void registerDisplayListener(DisplayManager.DisplayListener listener, Handler handler) {
193 mDisplayListener = listener;
194 }
195
196 @Override
197 String getActiveNetworkScorer() {
198 return null;
199 }
200
201 @Override
202 public boolean isBoundWidgetPackage(AppWidgetManager appWidgetManager, String packageName,
203 int userId) {
204 return packageName != null && packageName.equals(mBoundWidgetPackage);
205 }
206
Amith Yamasani301e94a2017-11-17 16:35:44 -0800207 @Override
208 String getAppIdleSettings() {
209 return "screen_thresholds=0/0/0/" + HOUR_MS + ",elapsed_thresholds=0/"
210 + WORKING_SET_THRESHOLD + "/"
211 + FREQUENT_THRESHOLD + "/"
212 + RARE_THRESHOLD;
213 }
214
Amith Yamasani17fffee2017-09-29 13:17:43 -0700215 // Internal methods
216
217 void setDisplayOn(boolean on) {
218 mDisplayOn = on;
219 if (mDisplayListener != null) {
220 mDisplayListener.onDisplayChanged(Display.DEFAULT_DISPLAY);
221 }
222 }
223 }
224
225 private void setupPm(PackageManager mockPm) throws PackageManager.NameNotFoundException {
226 List<PackageInfo> packages = new ArrayList<>();
227 PackageInfo pi = new PackageInfo();
228 pi.applicationInfo = new ApplicationInfo();
229 pi.applicationInfo.uid = UID_1;
230 pi.packageName = PACKAGE_1;
231 packages.add(pi);
232
Amith Yamasani777b1532018-01-28 23:20:07 +0000233 PackageInfo pie = new PackageInfo();
234 pie.applicationInfo = new ApplicationInfo();
235 pie.applicationInfo.uid = UID_EXEMPTED_1;
236 pie.packageName = PACKAGE_EXEMPTED_1;
237 packages.add(pie);
238
Amith Yamasani17fffee2017-09-29 13:17:43 -0700239 doReturn(packages).when(mockPm).getInstalledPackagesAsUser(anyInt(), anyInt());
240 try {
Amith Yamasani777b1532018-01-28 23:20:07 +0000241 doReturn(UID_1).when(mockPm).getPackageUidAsUser(eq(PACKAGE_1), anyInt(), anyInt());
242 doReturn(UID_EXEMPTED_1).when(mockPm).getPackageUidAsUser(eq(PACKAGE_EXEMPTED_1),
243 anyInt(), anyInt());
244 doReturn(pi.applicationInfo).when(mockPm).getApplicationInfo(eq(pi.packageName),
245 anyInt());
246 doReturn(pie.applicationInfo).when(mockPm).getApplicationInfo(eq(pie.packageName),
247 anyInt());
Amith Yamasani17fffee2017-09-29 13:17:43 -0700248 } catch (PackageManager.NameNotFoundException nnfe) {}
249 }
250
251 private void setChargingState(AppStandbyController controller, boolean charging) {
252 mInjector.mIsCharging = charging;
253 if (controller != null) {
254 controller.setChargingState(charging);
255 }
256 }
257
258 private AppStandbyController setupController() throws Exception {
259 mInjector.mElapsedRealtime = 0;
Amith Yamasani777b1532018-01-28 23:20:07 +0000260 setupPm(mInjector.getContext().getPackageManager());
Amith Yamasani17fffee2017-09-29 13:17:43 -0700261 AppStandbyController controller = new AppStandbyController(mInjector);
Amith Yamasani777b1532018-01-28 23:20:07 +0000262 controller.initializeDefaultsForSystemApps(USER_ID);
Amith Yamasani17fffee2017-09-29 13:17:43 -0700263 controller.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
264 controller.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
265 mInjector.setDisplayOn(false);
266 mInjector.setDisplayOn(true);
267 setChargingState(controller, false);
Amith Yamasani17fffee2017-09-29 13:17:43 -0700268 controller.checkIdleStates(USER_ID);
Amith Yamasani777b1532018-01-28 23:20:07 +0000269 assertEquals(STANDBY_BUCKET_EXEMPTED,
270 controller.getAppStandbyBucket(PACKAGE_EXEMPTED_1, USER_ID,
271 mInjector.mElapsedRealtime, false));
272 assertNotEquals(STANDBY_BUCKET_EXEMPTED,
273 controller.getAppStandbyBucket(PACKAGE_1, USER_ID,
274 mInjector.mElapsedRealtime, false));
Amith Yamasani17fffee2017-09-29 13:17:43 -0700275
276 return controller;
277 }
278
279 @Before
280 public void setUp() throws Exception {
281 MyContextWrapper myContext = new MyContextWrapper(InstrumentationRegistry.getContext());
282 mInjector = new MyInjector(myContext, Looper.getMainLooper());
Amith Yamasani93885192017-12-13 11:52:10 -0800283 mController = setupController();
Amith Yamasani17fffee2017-09-29 13:17:43 -0700284 }
285
286 @Test
287 public void testCharging() throws Exception {
Amith Yamasani93885192017-12-13 11:52:10 -0800288 setChargingState(mController, true);
Amith Yamasani301e94a2017-11-17 16:35:44 -0800289 mInjector.mElapsedRealtime = RARE_THRESHOLD + 1;
Amith Yamasani93885192017-12-13 11:52:10 -0800290 assertFalse(mController.isAppIdleFilteredOrParoled(PACKAGE_1, USER_ID,
Amith Yamasani17fffee2017-09-29 13:17:43 -0700291 mInjector.mElapsedRealtime, false));
292
Amith Yamasani93885192017-12-13 11:52:10 -0800293 setChargingState(mController, false);
Amith Yamasani301e94a2017-11-17 16:35:44 -0800294 mInjector.mElapsedRealtime = 2 * RARE_THRESHOLD + 2;
Amith Yamasani93885192017-12-13 11:52:10 -0800295 mController.checkIdleStates(USER_ID);
296 assertTrue(mController.isAppIdleFilteredOrParoled(PACKAGE_1, USER_ID,
Amith Yamasani17fffee2017-09-29 13:17:43 -0700297 mInjector.mElapsedRealtime, false));
Amith Yamasani93885192017-12-13 11:52:10 -0800298 setChargingState(mController, true);
299 assertFalse(mController.isAppIdleFilteredOrParoled(PACKAGE_1,USER_ID,
Amith Yamasani17fffee2017-09-29 13:17:43 -0700300 mInjector.mElapsedRealtime, false));
301 }
302
303 private void assertTimeout(AppStandbyController controller, long elapsedTime, int bucket) {
304 mInjector.mElapsedRealtime = elapsedTime;
305 controller.checkIdleStates(USER_ID);
306 assertEquals(bucket,
307 controller.getAppStandbyBucket(PACKAGE_1, USER_ID, mInjector.mElapsedRealtime,
308 false));
309 }
310
Amith Yamasani803eab692017-11-09 17:47:04 -0800311 private void reportEvent(AppStandbyController controller, int eventType,
312 long elapsedTime) {
Amith Yamasani84cd7b72017-11-07 13:59:37 -0800313 // Back to ACTIVE on event
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800314 mInjector.mElapsedRealtime = elapsedTime;
Amith Yamasani84cd7b72017-11-07 13:59:37 -0800315 UsageEvents.Event ev = new UsageEvents.Event();
316 ev.mPackage = PACKAGE_1;
Amith Yamasani803eab692017-11-09 17:47:04 -0800317 ev.mEventType = eventType;
Amith Yamasani84cd7b72017-11-07 13:59:37 -0800318 controller.reportEvent(ev, elapsedTime, USER_ID);
319 }
320
Amith Yamasani803eab692017-11-09 17:47:04 -0800321 private int getStandbyBucket(AppStandbyController controller) {
322 return controller.getAppStandbyBucket(PACKAGE_1, USER_ID, mInjector.mElapsedRealtime,
323 true);
324 }
325
Amith Yamasani53f06ea2018-01-05 17:53:46 -0800326 private void assertBucket(int bucket) {
327 assertEquals(bucket, getStandbyBucket(mController));
328 }
329
Amith Yamasani17fffee2017-09-29 13:17:43 -0700330 @Test
331 public void testBuckets() throws Exception {
Amith Yamasani93885192017-12-13 11:52:10 -0800332 assertTimeout(mController, 0, STANDBY_BUCKET_NEVER);
Amith Yamasani17fffee2017-09-29 13:17:43 -0700333
Amith Yamasani93885192017-12-13 11:52:10 -0800334 reportEvent(mController, USER_INTERACTION, 0);
Amith Yamasani84cd7b72017-11-07 13:59:37 -0800335
Amith Yamasani17fffee2017-09-29 13:17:43 -0700336 // ACTIVE bucket
Amith Yamasani93885192017-12-13 11:52:10 -0800337 assertTimeout(mController, WORKING_SET_THRESHOLD - 1, STANDBY_BUCKET_ACTIVE);
Amith Yamasani17fffee2017-09-29 13:17:43 -0700338
339 // WORKING_SET bucket
Amith Yamasani93885192017-12-13 11:52:10 -0800340 assertTimeout(mController, WORKING_SET_THRESHOLD + 1, STANDBY_BUCKET_WORKING_SET);
Amith Yamasani17fffee2017-09-29 13:17:43 -0700341
342 // WORKING_SET bucket
Amith Yamasani93885192017-12-13 11:52:10 -0800343 assertTimeout(mController, FREQUENT_THRESHOLD - 1, STANDBY_BUCKET_WORKING_SET);
Amith Yamasani17fffee2017-09-29 13:17:43 -0700344
345 // FREQUENT bucket
Amith Yamasani93885192017-12-13 11:52:10 -0800346 assertTimeout(mController, FREQUENT_THRESHOLD + 1, STANDBY_BUCKET_FREQUENT);
Amith Yamasani17fffee2017-09-29 13:17:43 -0700347
348 // RARE bucket
Amith Yamasani93885192017-12-13 11:52:10 -0800349 assertTimeout(mController, RARE_THRESHOLD + 1, STANDBY_BUCKET_RARE);
Amith Yamasani17fffee2017-09-29 13:17:43 -0700350
Amith Yamasani93885192017-12-13 11:52:10 -0800351 reportEvent(mController, USER_INTERACTION, RARE_THRESHOLD + 1);
Amith Yamasani17fffee2017-09-29 13:17:43 -0700352
Amith Yamasani93885192017-12-13 11:52:10 -0800353 assertTimeout(mController, RARE_THRESHOLD + 1, STANDBY_BUCKET_ACTIVE);
Amith Yamasani17fffee2017-09-29 13:17:43 -0700354
355 // RARE bucket
Amith Yamasani93885192017-12-13 11:52:10 -0800356 assertTimeout(mController, RARE_THRESHOLD * 2 + 2, STANDBY_BUCKET_RARE);
Amith Yamasani17fffee2017-09-29 13:17:43 -0700357 }
358
359 @Test
360 public void testScreenTimeAndBuckets() throws Exception {
Amith Yamasani17fffee2017-09-29 13:17:43 -0700361 mInjector.setDisplayOn(false);
362
Amith Yamasani93885192017-12-13 11:52:10 -0800363 assertTimeout(mController, 0, STANDBY_BUCKET_NEVER);
Amith Yamasani84cd7b72017-11-07 13:59:37 -0800364
Amith Yamasani93885192017-12-13 11:52:10 -0800365 reportEvent(mController, USER_INTERACTION, 0);
Amith Yamasani84cd7b72017-11-07 13:59:37 -0800366
Amith Yamasani17fffee2017-09-29 13:17:43 -0700367 // ACTIVE bucket
Amith Yamasani93885192017-12-13 11:52:10 -0800368 assertTimeout(mController, WORKING_SET_THRESHOLD - 1, STANDBY_BUCKET_ACTIVE);
Amith Yamasani17fffee2017-09-29 13:17:43 -0700369
370 // WORKING_SET bucket
Amith Yamasani93885192017-12-13 11:52:10 -0800371 assertTimeout(mController, WORKING_SET_THRESHOLD + 1, STANDBY_BUCKET_WORKING_SET);
Amith Yamasani17fffee2017-09-29 13:17:43 -0700372
373 // RARE bucket, should fail because the screen wasn't ON.
Amith Yamasani301e94a2017-11-17 16:35:44 -0800374 mInjector.mElapsedRealtime = RARE_THRESHOLD + 1;
Amith Yamasani93885192017-12-13 11:52:10 -0800375 mController.checkIdleStates(USER_ID);
376 assertNotEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController));
Amith Yamasani17fffee2017-09-29 13:17:43 -0700377
378 mInjector.setDisplayOn(true);
Amith Yamasani93885192017-12-13 11:52:10 -0800379 assertTimeout(mController, RARE_THRESHOLD * 2 + 2, STANDBY_BUCKET_RARE);
Amith Yamasani17fffee2017-09-29 13:17:43 -0700380 }
381
382 @Test
383 public void testForcedIdle() throws Exception {
Amith Yamasani93885192017-12-13 11:52:10 -0800384 setChargingState(mController, false);
Amith Yamasani17fffee2017-09-29 13:17:43 -0700385
Amith Yamasani93885192017-12-13 11:52:10 -0800386 mController.forceIdleState(PACKAGE_1, USER_ID, true);
387 assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController));
388 assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0));
Amith Yamasani17fffee2017-09-29 13:17:43 -0700389
Amith Yamasani93885192017-12-13 11:52:10 -0800390 mController.forceIdleState(PACKAGE_1, USER_ID, false);
391 assertEquals(STANDBY_BUCKET_ACTIVE, mController.getAppStandbyBucket(PACKAGE_1, USER_ID, 0,
Amith Yamasani17fffee2017-09-29 13:17:43 -0700392 true));
Amith Yamasani93885192017-12-13 11:52:10 -0800393 assertFalse(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0));
Amith Yamasani17fffee2017-09-29 13:17:43 -0700394 }
Amith Yamasani803eab692017-11-09 17:47:04 -0800395
396 @Test
397 public void testNotificationEvent() throws Exception {
Amith Yamasani93885192017-12-13 11:52:10 -0800398 setChargingState(mController, false);
Amith Yamasani803eab692017-11-09 17:47:04 -0800399
Amith Yamasani93885192017-12-13 11:52:10 -0800400 reportEvent(mController, USER_INTERACTION, 0);
401 assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController));
Amith Yamasani803eab692017-11-09 17:47:04 -0800402 mInjector.mElapsedRealtime = 1;
Amith Yamasani93885192017-12-13 11:52:10 -0800403 reportEvent(mController, NOTIFICATION_SEEN, mInjector.mElapsedRealtime);
404 assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController));
Amith Yamasani803eab692017-11-09 17:47:04 -0800405
Amith Yamasani93885192017-12-13 11:52:10 -0800406 mController.forceIdleState(PACKAGE_1, USER_ID, true);
407 reportEvent(mController, NOTIFICATION_SEEN, mInjector.mElapsedRealtime);
408 assertEquals(STANDBY_BUCKET_WORKING_SET, getStandbyBucket(mController));
Amith Yamasani803eab692017-11-09 17:47:04 -0800409 }
Amith Yamasanibd7b3022017-12-06 17:40:25 -0800410
411 @Test
Jason Monk1918ef72018-03-14 09:20:39 -0400412 public void testSlicePinnedEvent() throws Exception {
413 setChargingState(mController, false);
414
415 reportEvent(mController, USER_INTERACTION, 0);
416 assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController));
417 mInjector.mElapsedRealtime = 1;
418 reportEvent(mController, SLICE_PINNED, mInjector.mElapsedRealtime);
419 assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController));
420
421 mController.forceIdleState(PACKAGE_1, USER_ID, true);
422 reportEvent(mController, SLICE_PINNED, mInjector.mElapsedRealtime);
423 assertEquals(STANDBY_BUCKET_WORKING_SET, getStandbyBucket(mController));
424 }
425
426 @Test
427 public void testSlicePinnedPrivEvent() throws Exception {
428 setChargingState(mController, false);
429
430 mController.forceIdleState(PACKAGE_1, USER_ID, true);
431 reportEvent(mController, SLICE_PINNED_PRIV, mInjector.mElapsedRealtime);
432 assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController));
433 }
434
435 @Test
Amith Yamasanibd7b3022017-12-06 17:40:25 -0800436 public void testPredictionTimedout() throws Exception {
Amith Yamasani93885192017-12-13 11:52:10 -0800437 setChargingState(mController, false);
438 // Set it to timeout or usage, so that prediction can override it
439 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE,
Amith Yamasani119be9a2018-02-18 22:23:00 -0800440 REASON_MAIN_TIMEOUT, 1 * HOUR_MS);
Amith Yamasani93885192017-12-13 11:52:10 -0800441 assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController));
442
443 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE,
Amith Yamasani119be9a2018-02-18 22:23:00 -0800444 REASON_MAIN_PREDICTED, 1 * HOUR_MS);
Amith Yamasani93885192017-12-13 11:52:10 -0800445 assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController));
Amith Yamasanibd7b3022017-12-06 17:40:25 -0800446
447 // Fast forward 12 hours
448 mInjector.mElapsedRealtime += WORKING_SET_THRESHOLD;
Amith Yamasani93885192017-12-13 11:52:10 -0800449 mController.checkIdleStates(USER_ID);
Amith Yamasanibd7b3022017-12-06 17:40:25 -0800450 // Should still be in predicted bucket, since prediction timeout is 1 day since prediction
Amith Yamasani93885192017-12-13 11:52:10 -0800451 assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController));
Amith Yamasanibd7b3022017-12-06 17:40:25 -0800452 // Fast forward two more hours
453 mInjector.mElapsedRealtime += 2 * HOUR_MS;
Amith Yamasani93885192017-12-13 11:52:10 -0800454 mController.checkIdleStates(USER_ID);
Amith Yamasanibd7b3022017-12-06 17:40:25 -0800455 // Should have now applied prediction timeout
Amith Yamasani93885192017-12-13 11:52:10 -0800456 assertEquals(STANDBY_BUCKET_WORKING_SET, getStandbyBucket(mController));
Amith Yamasanibd7b3022017-12-06 17:40:25 -0800457
458 // Fast forward RARE bucket
459 mInjector.mElapsedRealtime += RARE_THRESHOLD;
Amith Yamasani93885192017-12-13 11:52:10 -0800460 mController.checkIdleStates(USER_ID);
Amith Yamasanibd7b3022017-12-06 17:40:25 -0800461 // Should continue to apply prediction timeout
Amith Yamasani93885192017-12-13 11:52:10 -0800462 assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController));
463 }
464
465 @Test
466 public void testOverrides() throws Exception {
467 setChargingState(mController, false);
468 // Can force to NEVER
469 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_NEVER,
Amith Yamasani119be9a2018-02-18 22:23:00 -0800470 REASON_MAIN_FORCED, 1 * HOUR_MS);
Amith Yamasani93885192017-12-13 11:52:10 -0800471 assertEquals(STANDBY_BUCKET_NEVER, getStandbyBucket(mController));
472
473 // Prediction can't override FORCED reason
474 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
Amith Yamasani119be9a2018-02-18 22:23:00 -0800475 REASON_MAIN_FORCED, 1 * HOUR_MS);
Amith Yamasani93885192017-12-13 11:52:10 -0800476 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_WORKING_SET,
Amith Yamasani119be9a2018-02-18 22:23:00 -0800477 REASON_MAIN_PREDICTED, 1 * HOUR_MS);
Amith Yamasani93885192017-12-13 11:52:10 -0800478 assertEquals(STANDBY_BUCKET_FREQUENT, getStandbyBucket(mController));
479
480 // Prediction can't override NEVER
481 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_NEVER,
Amith Yamasani119be9a2018-02-18 22:23:00 -0800482 REASON_MAIN_DEFAULT, 2 * HOUR_MS);
Amith Yamasani93885192017-12-13 11:52:10 -0800483 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE,
Amith Yamasani119be9a2018-02-18 22:23:00 -0800484 REASON_MAIN_PREDICTED, 2 * HOUR_MS);
Amith Yamasani93885192017-12-13 11:52:10 -0800485 assertEquals(STANDBY_BUCKET_NEVER, getStandbyBucket(mController));
486
487 // Prediction can't set to NEVER
488 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE,
Amith Yamasani119be9a2018-02-18 22:23:00 -0800489 REASON_MAIN_USAGE, 2 * HOUR_MS);
Amith Yamasani93885192017-12-13 11:52:10 -0800490 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_NEVER,
Amith Yamasani119be9a2018-02-18 22:23:00 -0800491 REASON_MAIN_PREDICTED, 2 * HOUR_MS);
Amith Yamasani93885192017-12-13 11:52:10 -0800492 assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController));
Amith Yamasanibd7b3022017-12-06 17:40:25 -0800493 }
Amith Yamasani53f06ea2018-01-05 17:53:46 -0800494
495 @Test
496 public void testTimeout() throws Exception {
497 setChargingState(mController, false);
498
499 reportEvent(mController, USER_INTERACTION, 0);
500 assertBucket(STANDBY_BUCKET_ACTIVE);
501
502 mInjector.mElapsedRealtime = 2000;
503 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
Amith Yamasani119be9a2018-02-18 22:23:00 -0800504 REASON_MAIN_PREDICTED, mInjector.mElapsedRealtime);
Amith Yamasani53f06ea2018-01-05 17:53:46 -0800505 assertBucket(STANDBY_BUCKET_ACTIVE);
506
507 // bucketing works after timeout
508 mInjector.mElapsedRealtime = FREQUENT_THRESHOLD - 100;
509 mController.checkIdleStates(USER_ID);
510 assertBucket(STANDBY_BUCKET_WORKING_SET);
511
512 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
Amith Yamasani119be9a2018-02-18 22:23:00 -0800513 REASON_MAIN_PREDICTED, mInjector.mElapsedRealtime);
Amith Yamasani53f06ea2018-01-05 17:53:46 -0800514 assertBucket(STANDBY_BUCKET_FREQUENT);
Sudheer Shanka101c3532018-01-08 16:28:42 -0800515 }
Amith Yamasani53f06ea2018-01-05 17:53:46 -0800516
Sudheer Shanka101c3532018-01-08 16:28:42 -0800517 @Test
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800518 public void testCascadingTimeouts() throws Exception {
519 setChargingState(mController, false);
520
521 reportEvent(mController, USER_INTERACTION, 0);
522 assertBucket(STANDBY_BUCKET_ACTIVE);
523
524 reportEvent(mController, NOTIFICATION_SEEN, 1000);
525 assertBucket(STANDBY_BUCKET_ACTIVE);
526
527 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_WORKING_SET,
Amith Yamasani119be9a2018-02-18 22:23:00 -0800528 REASON_MAIN_PREDICTED, 1000);
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800529 assertBucket(STANDBY_BUCKET_ACTIVE);
530
531 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
Amith Yamasani119be9a2018-02-18 22:23:00 -0800532 REASON_MAIN_PREDICTED, 2000 + mController.mStrongUsageTimeoutMillis);
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800533 assertBucket(STANDBY_BUCKET_WORKING_SET);
534
535 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
Amith Yamasani119be9a2018-02-18 22:23:00 -0800536 REASON_MAIN_PREDICTED, 2000 + mController.mNotificationSeenTimeoutMillis);
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800537 assertBucket(STANDBY_BUCKET_FREQUENT);
538 }
539
540 @Test
541 public void testOverlappingTimeouts() throws Exception {
542 setChargingState(mController, false);
543
544 reportEvent(mController, USER_INTERACTION, 0);
545 assertBucket(STANDBY_BUCKET_ACTIVE);
546
547 reportEvent(mController, NOTIFICATION_SEEN, 1000);
548 assertBucket(STANDBY_BUCKET_ACTIVE);
549
550 // Overlapping USER_INTERACTION before previous one times out
551 reportEvent(mController, USER_INTERACTION, mController.mStrongUsageTimeoutMillis - 1000);
552 assertBucket(STANDBY_BUCKET_ACTIVE);
553
554 // Still in ACTIVE after first USER_INTERACTION times out
555 mInjector.mElapsedRealtime = mController.mStrongUsageTimeoutMillis + 1000;
556 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
Amith Yamasani119be9a2018-02-18 22:23:00 -0800557 REASON_MAIN_PREDICTED, mInjector.mElapsedRealtime);
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800558 assertBucket(STANDBY_BUCKET_ACTIVE);
559
560 // Both timed out, so NOTIFICATION_SEEN timeout should be effective
561 mInjector.mElapsedRealtime = mController.mStrongUsageTimeoutMillis * 2 + 2000;
562 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
Amith Yamasani119be9a2018-02-18 22:23:00 -0800563 REASON_MAIN_PREDICTED, mInjector.mElapsedRealtime);
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800564 assertBucket(STANDBY_BUCKET_WORKING_SET);
565
566 mInjector.mElapsedRealtime = mController.mNotificationSeenTimeoutMillis + 2000;
567 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE,
Amith Yamasani119be9a2018-02-18 22:23:00 -0800568 REASON_MAIN_PREDICTED, mInjector.mElapsedRealtime);
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800569 assertBucket(STANDBY_BUCKET_RARE);
570 }
571
572 @Test
Amith Yamasani7f53c7b2018-03-25 21:55:50 -0700573 public void testSystemInteractionTimeout() throws Exception {
574 setChargingState(mController, false);
575
576 reportEvent(mController, USER_INTERACTION, 0);
577 // Fast forward to RARE
578 mInjector.mElapsedRealtime = RARE_THRESHOLD + 100;
579 mController.checkIdleStates(USER_ID);
580 assertBucket(STANDBY_BUCKET_RARE);
581
582 // Trigger a SYSTEM_INTERACTION and verify bucket
583 reportEvent(mController, SYSTEM_INTERACTION, mInjector.mElapsedRealtime);
584 assertBucket(STANDBY_BUCKET_ACTIVE);
585
586 // Verify it's still in ACTIVE close to end of timeout
587 mInjector.mElapsedRealtime += mController.mSystemInteractionTimeoutMillis - 100;
588 mController.checkIdleStates(USER_ID);
589 assertBucket(STANDBY_BUCKET_ACTIVE);
590
591 // Verify bucket moves to RARE after timeout
592 mInjector.mElapsedRealtime += 200;
593 mController.checkIdleStates(USER_ID);
594 assertBucket(STANDBY_BUCKET_RARE);
595 }
596
597 @Test
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800598 public void testPredictionNotOverridden() throws Exception {
599 setChargingState(mController, false);
600
601 reportEvent(mController, USER_INTERACTION, 0);
602 assertBucket(STANDBY_BUCKET_ACTIVE);
603
604 mInjector.mElapsedRealtime = WORKING_SET_THRESHOLD - 1000;
605 reportEvent(mController, NOTIFICATION_SEEN, mInjector.mElapsedRealtime);
606 assertBucket(STANDBY_BUCKET_ACTIVE);
607
608 // Falls back to WORKING_SET
609 mInjector.mElapsedRealtime += 5000;
610 mController.checkIdleStates(USER_ID);
611 assertBucket(STANDBY_BUCKET_WORKING_SET);
612
613 // Predict to ACTIVE
614 mInjector.mElapsedRealtime += 1000;
615 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE,
Amith Yamasani119be9a2018-02-18 22:23:00 -0800616 REASON_MAIN_PREDICTED, mInjector.mElapsedRealtime);
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800617 assertBucket(STANDBY_BUCKET_ACTIVE);
618
619 // CheckIdleStates should not change the prediction
620 mInjector.mElapsedRealtime += 1000;
621 mController.checkIdleStates(USER_ID);
622 assertBucket(STANDBY_BUCKET_ACTIVE);
623 }
624
625 @Test
Sudheer Shanka101c3532018-01-08 16:28:42 -0800626 public void testAddActiveDeviceAdmin() {
627 assertActiveAdmins(USER_ID, (String[]) null);
628 assertActiveAdmins(USER_ID2, (String[]) null);
629
630 mController.addActiveDeviceAdmin(ADMIN_PKG, USER_ID);
631 assertActiveAdmins(USER_ID, ADMIN_PKG);
632 assertActiveAdmins(USER_ID2, (String[]) null);
633
634 mController.addActiveDeviceAdmin(ADMIN_PKG, USER_ID);
635 assertActiveAdmins(USER_ID, ADMIN_PKG);
636 assertActiveAdmins(USER_ID2, (String[]) null);
637
638 mController.addActiveDeviceAdmin(ADMIN_PKG2, USER_ID2);
639 assertActiveAdmins(USER_ID, ADMIN_PKG);
640 assertActiveAdmins(USER_ID2, ADMIN_PKG2);
641 }
642
643 @Test
644 public void testSetActiveAdminApps() {
645 assertActiveAdmins(USER_ID, (String[]) null);
646 assertActiveAdmins(USER_ID2, (String[]) null);
647
648 setActiveAdmins(USER_ID, ADMIN_PKG, ADMIN_PKG2);
649 assertActiveAdmins(USER_ID, ADMIN_PKG, ADMIN_PKG2);
650 assertActiveAdmins(USER_ID2, (String[]) null);
651
652 mController.addActiveDeviceAdmin(ADMIN_PKG2, USER_ID2);
653 setActiveAdmins(USER_ID2, ADMIN_PKG);
654 assertActiveAdmins(USER_ID, ADMIN_PKG, ADMIN_PKG2);
655 assertActiveAdmins(USER_ID2, ADMIN_PKG);
656
657 mController.setActiveAdminApps(null, USER_ID);
658 assertActiveAdmins(USER_ID, (String[]) null);
659 }
660
661 @Test
662 public void isActiveDeviceAdmin() {
663 assertActiveAdmins(USER_ID, (String[]) null);
664 assertActiveAdmins(USER_ID2, (String[]) null);
665
666 mController.addActiveDeviceAdmin(ADMIN_PKG, USER_ID);
667 assertIsActiveAdmin(ADMIN_PKG, USER_ID);
668 assertIsNotActiveAdmin(ADMIN_PKG, USER_ID2);
669
670 mController.addActiveDeviceAdmin(ADMIN_PKG2, USER_ID2);
671 mController.addActiveDeviceAdmin(ADMIN_PKG, USER_ID2);
672 assertIsActiveAdmin(ADMIN_PKG, USER_ID);
673 assertIsNotActiveAdmin(ADMIN_PKG2, USER_ID);
674 assertIsActiveAdmin(ADMIN_PKG, USER_ID2);
675 assertIsActiveAdmin(ADMIN_PKG2, USER_ID2);
676
677 setActiveAdmins(USER_ID2, ADMIN_PKG2);
678 assertIsActiveAdmin(ADMIN_PKG2, USER_ID2);
679 assertIsNotActiveAdmin(ADMIN_PKG, USER_ID2);
680 assertIsActiveAdmin(ADMIN_PKG, USER_ID);
681 assertIsNotActiveAdmin(ADMIN_PKG2, USER_ID);
682 }
683
684 private String getAdminAppsStr(int userId) {
685 return getAdminAppsStr(userId, mController.getActiveAdminAppsForTest(userId));
686 }
687
688 private String getAdminAppsStr(int userId, Set<String> adminApps) {
689 return "admin apps for u" + userId + ": "
690 + (adminApps == null ? "null" : Arrays.toString(adminApps.toArray()));
691 }
692
693 private void assertIsActiveAdmin(String adminApp, int userId) {
694 assertTrue(adminApp + " should be an active admin; " + getAdminAppsStr(userId),
695 mController.isActiveDeviceAdmin(adminApp, userId));
696 }
697
698 private void assertIsNotActiveAdmin(String adminApp, int userId) {
699 assertFalse(adminApp + " shouldn't be an active admin; " + getAdminAppsStr(userId),
700 mController.isActiveDeviceAdmin(adminApp, userId));
701 }
702
703 private void assertActiveAdmins(int userId, String... admins) {
704 final Set<String> actualAdminApps = mController.getActiveAdminAppsForTest(userId);
705 if (admins == null) {
706 if (actualAdminApps != null && !actualAdminApps.isEmpty()) {
707 fail("Admin apps should be null; " + getAdminAppsStr(userId, actualAdminApps));
708 }
709 return;
710 }
711 assertEquals("No. of admin apps not equal; " + getAdminAppsStr(userId, actualAdminApps)
712 + "; expected=" + Arrays.toString(admins), admins.length, actualAdminApps.size());
713 final Set<String> adminAppsCopy = new ArraySet<>(actualAdminApps);
714 for (String admin : admins) {
715 adminAppsCopy.remove(admin);
716 }
717 assertTrue("Unexpected admin apps; " + getAdminAppsStr(userId, actualAdminApps)
718 + "; expected=" + Arrays.toString(admins), adminAppsCopy.isEmpty());
719 }
720
721 private void setActiveAdmins(int userId, String... admins) {
722 mController.setActiveAdminApps(new ArraySet<>(Arrays.asList(admins)), userId);
Amith Yamasani53f06ea2018-01-05 17:53:46 -0800723 }
Amith Yamasani17fffee2017-09-29 13:17:43 -0700724}