1 /* 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 17 package com.android.server.usage; 18 19 import static android.app.usage.UsageEvents.Event.NOTIFICATION_SEEN; 20 import static android.app.usage.UsageEvents.Event.SLICE_PINNED; 21 import static android.app.usage.UsageEvents.Event.SLICE_PINNED_PRIV; 22 import static android.app.usage.UsageEvents.Event.SYSTEM_INTERACTION; 23 import static android.app.usage.UsageEvents.Event.USER_INTERACTION; 24 import static android.app.usage.UsageStatsManager.REASON_MAIN_DEFAULT; 25 import static android.app.usage.UsageStatsManager.REASON_MAIN_FORCED; 26 import static android.app.usage.UsageStatsManager.REASON_MAIN_PREDICTED; 27 import static android.app.usage.UsageStatsManager.REASON_MAIN_TIMEOUT; 28 import static android.app.usage.UsageStatsManager.REASON_MAIN_USAGE; 29 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_ACTIVE; 30 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_EXEMPTED; 31 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_FREQUENT; 32 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_NEVER; 33 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RARE; 34 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_WORKING_SET; 35 36 import static org.junit.Assert.assertEquals; 37 import static org.junit.Assert.assertFalse; 38 import static org.junit.Assert.assertNotEquals; 39 import static org.junit.Assert.assertTrue; 40 41 import static org.junit.Assert.fail; 42 import static org.mockito.ArgumentMatchers.eq; 43 import static org.mockito.Matchers.anyInt; 44 import static org.mockito.Matchers.anyString; 45 import static org.mockito.Mockito.doReturn; 46 import static org.mockito.Mockito.mock; 47 48 import android.app.usage.UsageEvents; 49 import android.app.usage.UsageStatsManagerInternal; 50 import android.appwidget.AppWidgetManager; 51 import android.content.Context; 52 import android.content.ContextWrapper; 53 import android.content.pm.ApplicationInfo; 54 import android.content.pm.PackageInfo; 55 import android.content.pm.PackageManager; 56 import android.hardware.display.DisplayManager; 57 import android.os.Handler; 58 import android.os.Looper; 59 import android.os.RemoteException; 60 import android.platform.test.annotations.Presubmit; 61 import android.support.test.filters.SmallTest; 62 import android.support.test.InstrumentationRegistry; 63 import android.support.test.runner.AndroidJUnit4; 64 import android.util.ArraySet; 65 import android.view.Display; 66 67 import com.android.server.SystemService; 68 69 import org.junit.Before; 70 import org.junit.Test; 71 import org.junit.runner.RunWith; 72 73 import java.io.File; 74 import java.util.ArrayList; 75 import java.util.Arrays; 76 import java.util.List; 77 import java.util.Set; 78 import java.util.concurrent.CountDownLatch; 79 import java.util.concurrent.TimeUnit; 80 81 /** 82 * Unit test for AppStandbyController. 83 */ 84 @RunWith(AndroidJUnit4.class) 85 @Presubmit 86 @SmallTest 87 public class AppStandbyControllerTests { 88 89 private static final String PACKAGE_1 = "com.example.foo"; 90 private static final int UID_1 = 10000; 91 private static final String PACKAGE_EXEMPTED_1 = "com.android.exempted"; 92 private static final int UID_EXEMPTED_1 = 10001; 93 private static final int USER_ID = 0; 94 private static final int USER_ID2 = 10; 95 96 private static final String ADMIN_PKG = "com.android.admin"; 97 private static final String ADMIN_PKG2 = "com.android.admin2"; 98 private static final String ADMIN_PKG3 = "com.android.admin3"; 99 100 private static final long MINUTE_MS = 60 * 1000; 101 private static final long HOUR_MS = 60 * MINUTE_MS; 102 private static final long DAY_MS = 24 * HOUR_MS; 103 104 private static final long WORKING_SET_THRESHOLD = 12 * HOUR_MS; 105 private static final long FREQUENT_THRESHOLD = 24 * HOUR_MS; 106 private static final long RARE_THRESHOLD = 48 * HOUR_MS; 107 // Short STABLE_CHARGING_THRESHOLD for testing purposes 108 private static final long STABLE_CHARGING_THRESHOLD = 2000; 109 110 private MyInjector mInjector; 111 private AppStandbyController mController; 112 113 static class MyContextWrapper extends ContextWrapper { 114 PackageManager mockPm = mock(PackageManager.class); 115 116 public MyContextWrapper(Context base) { 117 super(base); 118 } 119 120 public PackageManager getPackageManager() { 121 return mockPm; 122 } 123 } 124 125 static class MyInjector extends AppStandbyController.Injector { 126 long mElapsedRealtime; 127 boolean mIsCharging; 128 List<String> mPowerSaveWhitelistExceptIdle = new ArrayList<>(); 129 boolean mDisplayOn; 130 DisplayManager.DisplayListener mDisplayListener; 131 String mBoundWidgetPackage = PACKAGE_EXEMPTED_1; 132 133 MyInjector(Context context, Looper looper) { 134 super(context, looper); 135 } 136 137 @Override 138 void onBootPhase(int phase) { 139 } 140 141 @Override 142 int getBootPhase() { 143 return SystemService.PHASE_BOOT_COMPLETED; 144 } 145 146 @Override 147 long elapsedRealtime() { 148 return mElapsedRealtime; 149 } 150 151 @Override 152 long currentTimeMillis() { 153 return mElapsedRealtime; 154 } 155 156 @Override 157 boolean isAppIdleEnabled() { 158 return true; 159 } 160 161 @Override 162 boolean isCharging() { 163 return mIsCharging; 164 } 165 166 @Override 167 boolean isPowerSaveWhitelistExceptIdleApp(String packageName) throws RemoteException { 168 return mPowerSaveWhitelistExceptIdle.contains(packageName); 169 } 170 171 @Override 172 File getDataSystemDirectory() { 173 return new File(getContext().getFilesDir(), Long.toString(Math.randomLongInternal())); 174 } 175 176 @Override 177 void noteEvent(int event, String packageName, int uid) throws RemoteException { 178 } 179 180 @Override 181 boolean isPackageEphemeral(int userId, String packageName) { 182 // TODO: update when testing ephemeral apps scenario 183 return false; 184 } 185 186 @Override 187 int[] getRunningUserIds() { 188 return new int[] {USER_ID}; 189 } 190 191 @Override 192 boolean isDefaultDisplayOn() { 193 return mDisplayOn; 194 } 195 196 @Override 197 void registerDisplayListener(DisplayManager.DisplayListener listener, Handler handler) { 198 mDisplayListener = listener; 199 } 200 201 @Override 202 String getActiveNetworkScorer() { 203 return null; 204 } 205 206 @Override 207 public boolean isBoundWidgetPackage(AppWidgetManager appWidgetManager, String packageName, 208 int userId) { 209 return packageName != null && packageName.equals(mBoundWidgetPackage); 210 } 211 212 @Override 213 String getAppIdleSettings() { 214 return "screen_thresholds=0/0/0/" + HOUR_MS + ",elapsed_thresholds=0/" 215 + WORKING_SET_THRESHOLD + "/" 216 + FREQUENT_THRESHOLD + "/" 217 + RARE_THRESHOLD + "," 218 + "stable_charging_threshold=" + STABLE_CHARGING_THRESHOLD; 219 } 220 221 @Override 222 public boolean isDeviceIdleMode() { 223 return false; 224 } 225 226 // Internal methods 227 228 void setDisplayOn(boolean on) { 229 mDisplayOn = on; 230 if (mDisplayListener != null) { 231 mDisplayListener.onDisplayChanged(Display.DEFAULT_DISPLAY); 232 } 233 } 234 } 235 236 private void setupPm(PackageManager mockPm) throws PackageManager.NameNotFoundException { 237 List<PackageInfo> packages = new ArrayList<>(); 238 PackageInfo pi = new PackageInfo(); 239 pi.applicationInfo = new ApplicationInfo(); 240 pi.applicationInfo.uid = UID_1; 241 pi.packageName = PACKAGE_1; 242 packages.add(pi); 243 244 PackageInfo pie = new PackageInfo(); 245 pie.applicationInfo = new ApplicationInfo(); 246 pie.applicationInfo.uid = UID_EXEMPTED_1; 247 pie.packageName = PACKAGE_EXEMPTED_1; 248 packages.add(pie); 249 250 doReturn(packages).when(mockPm).getInstalledPackagesAsUser(anyInt(), anyInt()); 251 try { 252 doReturn(UID_1).when(mockPm).getPackageUidAsUser(eq(PACKAGE_1), anyInt(), anyInt()); 253 doReturn(UID_EXEMPTED_1).when(mockPm).getPackageUidAsUser(eq(PACKAGE_EXEMPTED_1), 254 anyInt(), anyInt()); 255 doReturn(pi.applicationInfo).when(mockPm).getApplicationInfo(eq(pi.packageName), 256 anyInt()); 257 doReturn(pie.applicationInfo).when(mockPm).getApplicationInfo(eq(pie.packageName), 258 anyInt()); 259 } catch (PackageManager.NameNotFoundException nnfe) {} 260 } 261 262 private void setChargingState(AppStandbyController controller, boolean charging) { 263 mInjector.mIsCharging = charging; 264 if (controller != null) { 265 controller.setChargingState(charging); 266 } 267 } 268 269 private AppStandbyController setupController() throws Exception { 270 mInjector.mElapsedRealtime = 0; 271 setupPm(mInjector.getContext().getPackageManager()); 272 AppStandbyController controller = new AppStandbyController(mInjector); 273 controller.initializeDefaultsForSystemApps(USER_ID); 274 controller.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY); 275 controller.onBootPhase(SystemService.PHASE_BOOT_COMPLETED); 276 mInjector.setDisplayOn(false); 277 mInjector.setDisplayOn(true); 278 setChargingState(controller, false); 279 controller.checkIdleStates(USER_ID); 280 assertEquals(STANDBY_BUCKET_EXEMPTED, 281 controller.getAppStandbyBucket(PACKAGE_EXEMPTED_1, USER_ID, 282 mInjector.mElapsedRealtime, false)); 283 assertNotEquals(STANDBY_BUCKET_EXEMPTED, 284 controller.getAppStandbyBucket(PACKAGE_1, USER_ID, 285 mInjector.mElapsedRealtime, false)); 286 287 return controller; 288 } 289 290 private long getCurrentTime() { 291 return TimeUnit.NANOSECONDS.toMillis(System.nanoTime()); 292 } 293 294 @Before 295 public void setUp() throws Exception { 296 MyContextWrapper myContext = new MyContextWrapper(InstrumentationRegistry.getContext()); 297 mInjector = new MyInjector(myContext, Looper.getMainLooper()); 298 mController = setupController(); 299 setChargingState(mController, false); 300 } 301 302 private class TestParoleListener extends UsageStatsManagerInternal.AppIdleStateChangeListener { 303 private boolean mOnParole = false; 304 private CountDownLatch mLatch; 305 private long mLastParoleChangeTime; 306 307 public boolean getParoleState() { 308 synchronized (this) { 309 return mOnParole; 310 } 311 } 312 313 public void rearmLatch() { 314 synchronized (this) { 315 mLatch = new CountDownLatch(1); 316 } 317 } 318 319 public void awaitOnLatch(long time) throws Exception { 320 mLatch.await(time, TimeUnit.MILLISECONDS); 321 } 322 323 public long getLastParoleChangeTime() { 324 synchronized (this) { 325 return mLastParoleChangeTime; 326 } 327 } 328 329 @Override 330 public void onAppIdleStateChanged(String packageName, int userId, boolean idle, 331 int bucket, int reason) { 332 } 333 334 @Override 335 public void onParoleStateChanged(boolean isParoleOn) { 336 synchronized (this) { 337 // Only record information if it is being looked for 338 if (mLatch.getCount() > 0) { 339 mOnParole = isParoleOn; 340 mLastParoleChangeTime = getCurrentTime(); 341 mLatch.countDown(); 342 } 343 } 344 } 345 } 346 347 @Test 348 public void testCharging() throws Exception { 349 long startTime; 350 TestParoleListener paroleListener = new TestParoleListener(); 351 long marginOfError = 200; 352 353 // Charging 354 paroleListener.rearmLatch(); 355 mController.addListener(paroleListener); 356 startTime = getCurrentTime(); 357 setChargingState(mController, true); 358 paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2); 359 assertTrue(paroleListener.mOnParole); 360 // Parole will only be granted after device has been charging for a sufficient amount of 361 // time. 362 assertEquals(STABLE_CHARGING_THRESHOLD, 363 paroleListener.getLastParoleChangeTime() - startTime, 364 marginOfError); 365 366 // Discharging 367 paroleListener.rearmLatch(); 368 startTime = getCurrentTime(); 369 setChargingState(mController, false); 370 mController.checkIdleStates(USER_ID); 371 paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2); 372 assertFalse(paroleListener.getParoleState()); 373 // Parole should be revoked immediately 374 assertEquals(0, 375 paroleListener.getLastParoleChangeTime() - startTime, 376 marginOfError); 377 378 // Brief Charging 379 paroleListener.rearmLatch(); 380 setChargingState(mController, true); 381 setChargingState(mController, false); 382 // Device stopped charging before the stable charging threshold. 383 // Parole should not be granted at the end of the threshold 384 paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2); 385 assertFalse(paroleListener.getParoleState()); 386 387 // Charging Again 388 paroleListener.rearmLatch(); 389 startTime = getCurrentTime(); 390 setChargingState(mController, true); 391 paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2); 392 assertTrue(paroleListener.getParoleState()); 393 assertTrue(paroleListener.mOnParole); 394 assertEquals(STABLE_CHARGING_THRESHOLD, 395 paroleListener.getLastParoleChangeTime() - startTime, 396 marginOfError); 397 } 398 399 private void assertTimeout(AppStandbyController controller, long elapsedTime, int bucket) { 400 mInjector.mElapsedRealtime = elapsedTime; 401 controller.checkIdleStates(USER_ID); 402 assertEquals(bucket, 403 controller.getAppStandbyBucket(PACKAGE_1, USER_ID, mInjector.mElapsedRealtime, 404 false)); 405 } 406 407 private void reportEvent(AppStandbyController controller, int eventType, 408 long elapsedTime) { 409 // Back to ACTIVE on event 410 mInjector.mElapsedRealtime = elapsedTime; 411 UsageEvents.Event ev = new UsageEvents.Event(); 412 ev.mPackage = PACKAGE_1; 413 ev.mEventType = eventType; 414 controller.reportEvent(ev, elapsedTime, USER_ID); 415 } 416 417 private int getStandbyBucket(AppStandbyController controller) { 418 return controller.getAppStandbyBucket(PACKAGE_1, USER_ID, mInjector.mElapsedRealtime, 419 true); 420 } 421 422 private void assertBucket(int bucket) { 423 assertEquals(bucket, getStandbyBucket(mController)); 424 } 425 426 @Test 427 public void testBuckets() throws Exception { 428 assertTimeout(mController, 0, STANDBY_BUCKET_NEVER); 429 430 reportEvent(mController, USER_INTERACTION, 0); 431 432 // ACTIVE bucket 433 assertTimeout(mController, WORKING_SET_THRESHOLD - 1, STANDBY_BUCKET_ACTIVE); 434 435 // WORKING_SET bucket 436 assertTimeout(mController, WORKING_SET_THRESHOLD + 1, STANDBY_BUCKET_WORKING_SET); 437 438 // WORKING_SET bucket 439 assertTimeout(mController, FREQUENT_THRESHOLD - 1, STANDBY_BUCKET_WORKING_SET); 440 441 // FREQUENT bucket 442 assertTimeout(mController, FREQUENT_THRESHOLD + 1, STANDBY_BUCKET_FREQUENT); 443 444 // RARE bucket 445 assertTimeout(mController, RARE_THRESHOLD + 1, STANDBY_BUCKET_RARE); 446 447 reportEvent(mController, USER_INTERACTION, RARE_THRESHOLD + 1); 448 449 assertTimeout(mController, RARE_THRESHOLD + 1, STANDBY_BUCKET_ACTIVE); 450 451 // RARE bucket 452 assertTimeout(mController, RARE_THRESHOLD * 2 + 2, STANDBY_BUCKET_RARE); 453 } 454 455 @Test 456 public void testScreenTimeAndBuckets() throws Exception { 457 mInjector.setDisplayOn(false); 458 459 assertTimeout(mController, 0, STANDBY_BUCKET_NEVER); 460 461 reportEvent(mController, USER_INTERACTION, 0); 462 463 // ACTIVE bucket 464 assertTimeout(mController, WORKING_SET_THRESHOLD - 1, STANDBY_BUCKET_ACTIVE); 465 466 // WORKING_SET bucket 467 assertTimeout(mController, WORKING_SET_THRESHOLD + 1, STANDBY_BUCKET_WORKING_SET); 468 469 // RARE bucket, should fail because the screen wasn't ON. 470 mInjector.mElapsedRealtime = RARE_THRESHOLD + 1; 471 mController.checkIdleStates(USER_ID); 472 assertNotEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController)); 473 474 mInjector.setDisplayOn(true); 475 assertTimeout(mController, RARE_THRESHOLD * 2 + 2, STANDBY_BUCKET_RARE); 476 } 477 478 @Test 479 public void testForcedIdle() throws Exception { 480 mController.forceIdleState(PACKAGE_1, USER_ID, true); 481 assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController)); 482 assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0)); 483 484 mController.forceIdleState(PACKAGE_1, USER_ID, false); 485 assertEquals(STANDBY_BUCKET_ACTIVE, mController.getAppStandbyBucket(PACKAGE_1, USER_ID, 0, 486 true)); 487 assertFalse(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0)); 488 } 489 490 @Test 491 public void testNotificationEvent() throws Exception { 492 reportEvent(mController, USER_INTERACTION, 0); 493 assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController)); 494 mInjector.mElapsedRealtime = 1; 495 reportEvent(mController, NOTIFICATION_SEEN, mInjector.mElapsedRealtime); 496 assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController)); 497 498 mController.forceIdleState(PACKAGE_1, USER_ID, true); 499 reportEvent(mController, NOTIFICATION_SEEN, mInjector.mElapsedRealtime); 500 assertEquals(STANDBY_BUCKET_WORKING_SET, getStandbyBucket(mController)); 501 } 502 503 @Test 504 public void testSlicePinnedEvent() throws Exception { 505 reportEvent(mController, USER_INTERACTION, 0); 506 assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController)); 507 mInjector.mElapsedRealtime = 1; 508 reportEvent(mController, SLICE_PINNED, mInjector.mElapsedRealtime); 509 assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController)); 510 511 mController.forceIdleState(PACKAGE_1, USER_ID, true); 512 reportEvent(mController, SLICE_PINNED, mInjector.mElapsedRealtime); 513 assertEquals(STANDBY_BUCKET_WORKING_SET, getStandbyBucket(mController)); 514 } 515 516 @Test 517 public void testSlicePinnedPrivEvent() throws Exception { 518 mController.forceIdleState(PACKAGE_1, USER_ID, true); 519 reportEvent(mController, SLICE_PINNED_PRIV, mInjector.mElapsedRealtime); 520 assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController)); 521 } 522 523 @Test 524 public void testPredictionTimedout() throws Exception { 525 // Set it to timeout or usage, so that prediction can override it 526 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE, 527 REASON_MAIN_TIMEOUT, HOUR_MS); 528 assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController)); 529 530 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE, 531 REASON_MAIN_PREDICTED, HOUR_MS); 532 assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController)); 533 534 // Fast forward 12 hours 535 mInjector.mElapsedRealtime += WORKING_SET_THRESHOLD; 536 mController.checkIdleStates(USER_ID); 537 // Should still be in predicted bucket, since prediction timeout is 1 day since prediction 538 assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController)); 539 // Fast forward two more hours 540 mInjector.mElapsedRealtime += 2 * HOUR_MS; 541 mController.checkIdleStates(USER_ID); 542 // Should have now applied prediction timeout 543 assertEquals(STANDBY_BUCKET_WORKING_SET, getStandbyBucket(mController)); 544 545 // Fast forward RARE bucket 546 mInjector.mElapsedRealtime += RARE_THRESHOLD; 547 mController.checkIdleStates(USER_ID); 548 // Should continue to apply prediction timeout 549 assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController)); 550 } 551 552 @Test 553 public void testOverrides() throws Exception { 554 // Can force to NEVER 555 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_NEVER, 556 REASON_MAIN_FORCED, 1 * HOUR_MS); 557 assertEquals(STANDBY_BUCKET_NEVER, getStandbyBucket(mController)); 558 559 // Prediction can't override FORCED reason 560 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT, 561 REASON_MAIN_FORCED, 1 * HOUR_MS); 562 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_WORKING_SET, 563 REASON_MAIN_PREDICTED, 1 * HOUR_MS); 564 assertEquals(STANDBY_BUCKET_FREQUENT, getStandbyBucket(mController)); 565 566 // Prediction can't override NEVER 567 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_NEVER, 568 REASON_MAIN_DEFAULT, 2 * HOUR_MS); 569 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE, 570 REASON_MAIN_PREDICTED, 2 * HOUR_MS); 571 assertEquals(STANDBY_BUCKET_NEVER, getStandbyBucket(mController)); 572 573 // Prediction can't set to NEVER 574 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE, 575 REASON_MAIN_USAGE, 2 * HOUR_MS); 576 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_NEVER, 577 REASON_MAIN_PREDICTED, 2 * HOUR_MS); 578 assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController)); 579 } 580 581 @Test 582 public void testTimeout() throws Exception { 583 reportEvent(mController, USER_INTERACTION, 0); 584 assertBucket(STANDBY_BUCKET_ACTIVE); 585 586 mInjector.mElapsedRealtime = 2000; 587 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT, 588 REASON_MAIN_PREDICTED, mInjector.mElapsedRealtime); 589 assertBucket(STANDBY_BUCKET_ACTIVE); 590 591 // bucketing works after timeout 592 mInjector.mElapsedRealtime = mController.mPredictionTimeoutMillis - 100; 593 mController.checkIdleStates(USER_ID); 594 // Use recent prediction 595 assertBucket(STANDBY_BUCKET_FREQUENT); 596 597 // Way past prediction timeout, use system thresholds 598 mInjector.mElapsedRealtime = RARE_THRESHOLD * 4; 599 mController.checkIdleStates(USER_ID); 600 assertBucket(STANDBY_BUCKET_RARE); 601 } 602 603 @Test 604 public void testCascadingTimeouts() throws Exception { 605 reportEvent(mController, USER_INTERACTION, 0); 606 assertBucket(STANDBY_BUCKET_ACTIVE); 607 608 reportEvent(mController, NOTIFICATION_SEEN, 1000); 609 assertBucket(STANDBY_BUCKET_ACTIVE); 610 611 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_WORKING_SET, 612 REASON_MAIN_PREDICTED, 1000); 613 assertBucket(STANDBY_BUCKET_ACTIVE); 614 615 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT, 616 REASON_MAIN_PREDICTED, 2000 + mController.mStrongUsageTimeoutMillis); 617 assertBucket(STANDBY_BUCKET_WORKING_SET); 618 619 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT, 620 REASON_MAIN_PREDICTED, 2000 + mController.mNotificationSeenTimeoutMillis); 621 assertBucket(STANDBY_BUCKET_FREQUENT); 622 } 623 624 @Test 625 public void testOverlappingTimeouts() throws Exception { 626 reportEvent(mController, USER_INTERACTION, 0); 627 assertBucket(STANDBY_BUCKET_ACTIVE); 628 629 reportEvent(mController, NOTIFICATION_SEEN, 1000); 630 assertBucket(STANDBY_BUCKET_ACTIVE); 631 632 // Overlapping USER_INTERACTION before previous one times out 633 reportEvent(mController, USER_INTERACTION, mController.mStrongUsageTimeoutMillis - 1000); 634 assertBucket(STANDBY_BUCKET_ACTIVE); 635 636 // Still in ACTIVE after first USER_INTERACTION times out 637 mInjector.mElapsedRealtime = mController.mStrongUsageTimeoutMillis + 1000; 638 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT, 639 REASON_MAIN_PREDICTED, mInjector.mElapsedRealtime); 640 assertBucket(STANDBY_BUCKET_ACTIVE); 641 642 // Both timed out, so NOTIFICATION_SEEN timeout should be effective 643 mInjector.mElapsedRealtime = mController.mStrongUsageTimeoutMillis * 2 + 2000; 644 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT, 645 REASON_MAIN_PREDICTED, mInjector.mElapsedRealtime); 646 assertBucket(STANDBY_BUCKET_WORKING_SET); 647 648 mInjector.mElapsedRealtime = mController.mNotificationSeenTimeoutMillis + 2000; 649 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE, 650 REASON_MAIN_PREDICTED, mInjector.mElapsedRealtime); 651 assertBucket(STANDBY_BUCKET_RARE); 652 } 653 654 @Test 655 public void testSystemInteractionTimeout() throws Exception { 656 setChargingState(mController, false); 657 658 reportEvent(mController, USER_INTERACTION, 0); 659 // Fast forward to RARE 660 mInjector.mElapsedRealtime = RARE_THRESHOLD + 100; 661 mController.checkIdleStates(USER_ID); 662 assertBucket(STANDBY_BUCKET_RARE); 663 664 // Trigger a SYSTEM_INTERACTION and verify bucket 665 reportEvent(mController, SYSTEM_INTERACTION, mInjector.mElapsedRealtime); 666 assertBucket(STANDBY_BUCKET_ACTIVE); 667 668 // Verify it's still in ACTIVE close to end of timeout 669 mInjector.mElapsedRealtime += mController.mSystemInteractionTimeoutMillis - 100; 670 mController.checkIdleStates(USER_ID); 671 assertBucket(STANDBY_BUCKET_ACTIVE); 672 673 // Verify bucket moves to RARE after timeout 674 mInjector.mElapsedRealtime += 200; 675 mController.checkIdleStates(USER_ID); 676 assertBucket(STANDBY_BUCKET_RARE); 677 } 678 679 @Test 680 public void testPredictionNotOverridden() throws Exception { 681 reportEvent(mController, USER_INTERACTION, 0); 682 assertBucket(STANDBY_BUCKET_ACTIVE); 683 684 mInjector.mElapsedRealtime = WORKING_SET_THRESHOLD - 1000; 685 reportEvent(mController, NOTIFICATION_SEEN, mInjector.mElapsedRealtime); 686 assertBucket(STANDBY_BUCKET_ACTIVE); 687 688 // Falls back to WORKING_SET 689 mInjector.mElapsedRealtime += 5000; 690 mController.checkIdleStates(USER_ID); 691 assertBucket(STANDBY_BUCKET_WORKING_SET); 692 693 // Predict to ACTIVE 694 mInjector.mElapsedRealtime += 1000; 695 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE, 696 REASON_MAIN_PREDICTED, mInjector.mElapsedRealtime); 697 assertBucket(STANDBY_BUCKET_ACTIVE); 698 699 // CheckIdleStates should not change the prediction 700 mInjector.mElapsedRealtime += 1000; 701 mController.checkIdleStates(USER_ID); 702 assertBucket(STANDBY_BUCKET_ACTIVE); 703 } 704 705 @Test 706 public void testPredictionStrikesBack() throws Exception { 707 reportEvent(mController, USER_INTERACTION, 0); 708 assertBucket(STANDBY_BUCKET_ACTIVE); 709 710 // Predict to FREQUENT 711 mInjector.mElapsedRealtime = RARE_THRESHOLD; 712 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT, 713 REASON_MAIN_PREDICTED, mInjector.mElapsedRealtime); 714 assertBucket(STANDBY_BUCKET_FREQUENT); 715 716 // Add a short timeout event 717 mInjector.mElapsedRealtime += 1000; 718 reportEvent(mController, SYSTEM_INTERACTION, mInjector.mElapsedRealtime); 719 assertBucket(STANDBY_BUCKET_ACTIVE); 720 mInjector.mElapsedRealtime += 1000; 721 mController.checkIdleStates(USER_ID); 722 assertBucket(STANDBY_BUCKET_ACTIVE); 723 724 // Verify it reverted to predicted 725 mInjector.mElapsedRealtime += WORKING_SET_THRESHOLD / 2; 726 mController.checkIdleStates(USER_ID); 727 assertBucket(STANDBY_BUCKET_FREQUENT); 728 } 729 730 @Test 731 public void testAddActiveDeviceAdmin() { 732 assertActiveAdmins(USER_ID, (String[]) null); 733 assertActiveAdmins(USER_ID2, (String[]) null); 734 735 mController.addActiveDeviceAdmin(ADMIN_PKG, USER_ID); 736 assertActiveAdmins(USER_ID, ADMIN_PKG); 737 assertActiveAdmins(USER_ID2, (String[]) null); 738 739 mController.addActiveDeviceAdmin(ADMIN_PKG, USER_ID); 740 assertActiveAdmins(USER_ID, ADMIN_PKG); 741 assertActiveAdmins(USER_ID2, (String[]) null); 742 743 mController.addActiveDeviceAdmin(ADMIN_PKG2, USER_ID2); 744 assertActiveAdmins(USER_ID, ADMIN_PKG); 745 assertActiveAdmins(USER_ID2, ADMIN_PKG2); 746 } 747 748 @Test 749 public void testSetActiveAdminApps() { 750 assertActiveAdmins(USER_ID, (String[]) null); 751 assertActiveAdmins(USER_ID2, (String[]) null); 752 753 setActiveAdmins(USER_ID, ADMIN_PKG, ADMIN_PKG2); 754 assertActiveAdmins(USER_ID, ADMIN_PKG, ADMIN_PKG2); 755 assertActiveAdmins(USER_ID2, (String[]) null); 756 757 mController.addActiveDeviceAdmin(ADMIN_PKG2, USER_ID2); 758 setActiveAdmins(USER_ID2, ADMIN_PKG); 759 assertActiveAdmins(USER_ID, ADMIN_PKG, ADMIN_PKG2); 760 assertActiveAdmins(USER_ID2, ADMIN_PKG); 761 762 mController.setActiveAdminApps(null, USER_ID); 763 assertActiveAdmins(USER_ID, (String[]) null); 764 } 765 766 @Test 767 public void isActiveDeviceAdmin() { 768 assertActiveAdmins(USER_ID, (String[]) null); 769 assertActiveAdmins(USER_ID2, (String[]) null); 770 771 mController.addActiveDeviceAdmin(ADMIN_PKG, USER_ID); 772 assertIsActiveAdmin(ADMIN_PKG, USER_ID); 773 assertIsNotActiveAdmin(ADMIN_PKG, USER_ID2); 774 775 mController.addActiveDeviceAdmin(ADMIN_PKG2, USER_ID2); 776 mController.addActiveDeviceAdmin(ADMIN_PKG, USER_ID2); 777 assertIsActiveAdmin(ADMIN_PKG, USER_ID); 778 assertIsNotActiveAdmin(ADMIN_PKG2, USER_ID); 779 assertIsActiveAdmin(ADMIN_PKG, USER_ID2); 780 assertIsActiveAdmin(ADMIN_PKG2, USER_ID2); 781 782 setActiveAdmins(USER_ID2, ADMIN_PKG2); 783 assertIsActiveAdmin(ADMIN_PKG2, USER_ID2); 784 assertIsNotActiveAdmin(ADMIN_PKG, USER_ID2); 785 assertIsActiveAdmin(ADMIN_PKG, USER_ID); 786 assertIsNotActiveAdmin(ADMIN_PKG2, USER_ID); 787 } 788 789 private String getAdminAppsStr(int userId) { 790 return getAdminAppsStr(userId, mController.getActiveAdminAppsForTest(userId)); 791 } 792 793 private String getAdminAppsStr(int userId, Set<String> adminApps) { 794 return "admin apps for u" + userId + ": " 795 + (adminApps == null ? "null" : Arrays.toString(adminApps.toArray())); 796 } 797 798 private void assertIsActiveAdmin(String adminApp, int userId) { 799 assertTrue(adminApp + " should be an active admin; " + getAdminAppsStr(userId), 800 mController.isActiveDeviceAdmin(adminApp, userId)); 801 } 802 803 private void assertIsNotActiveAdmin(String adminApp, int userId) { 804 assertFalse(adminApp + " shouldn't be an active admin; " + getAdminAppsStr(userId), 805 mController.isActiveDeviceAdmin(adminApp, userId)); 806 } 807 808 private void assertActiveAdmins(int userId, String... admins) { 809 final Set<String> actualAdminApps = mController.getActiveAdminAppsForTest(userId); 810 if (admins == null) { 811 if (actualAdminApps != null && !actualAdminApps.isEmpty()) { 812 fail("Admin apps should be null; " + getAdminAppsStr(userId, actualAdminApps)); 813 } 814 return; 815 } 816 assertEquals("No. of admin apps not equal; " + getAdminAppsStr(userId, actualAdminApps) 817 + "; expected=" + Arrays.toString(admins), admins.length, actualAdminApps.size()); 818 final Set<String> adminAppsCopy = new ArraySet<>(actualAdminApps); 819 for (String admin : admins) { 820 adminAppsCopy.remove(admin); 821 } 822 assertTrue("Unexpected admin apps; " + getAdminAppsStr(userId, actualAdminApps) 823 + "; expected=" + Arrays.toString(admins), adminAppsCopy.isEmpty()); 824 } 825 826 private void setActiveAdmins(int userId, String... admins) { 827 mController.setActiveAdminApps(new ArraySet<>(Arrays.asList(admins)), userId); 828 } 829 } 830