Loading services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java +91 −56 Original line number Diff line number Diff line Loading @@ -18,9 +18,14 @@ package com.android.server.usage; import static android.app.usage.UsageEvents.Event.NOTIFICATION_SEEN; import static android.app.usage.UsageEvents.Event.USER_INTERACTION; import static android.app.usage.UsageStatsManager.REASON_DEFAULT; import static android.app.usage.UsageStatsManager.REASON_FORCED; import static android.app.usage.UsageStatsManager.REASON_PREDICTED; import static android.app.usage.UsageStatsManager.REASON_TIMEOUT; import static android.app.usage.UsageStatsManager.REASON_USAGE; import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_ACTIVE; import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_FREQUENT; import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_NEVER; import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RARE; import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_WORKING_SET; Loading Loading @@ -79,6 +84,7 @@ public class AppStandbyControllerTests { private static final long RARE_THRESHOLD = 48 * HOUR_MS; private MyInjector mInjector; private AppStandbyController mController; static class MyContextWrapper extends ContextWrapper { PackageManager mockPm = mock(PackageManager.class); Loading Loading @@ -237,24 +243,23 @@ public class AppStandbyControllerTests { public void setUp() throws Exception { MyContextWrapper myContext = new MyContextWrapper(InstrumentationRegistry.getContext()); mInjector = new MyInjector(myContext, Looper.getMainLooper()); mController = setupController(); } @Test public void testCharging() throws Exception { AppStandbyController controller = setupController(); setChargingState(controller, true); setChargingState(mController, true); mInjector.mElapsedRealtime = RARE_THRESHOLD + 1; assertFalse(controller.isAppIdleFilteredOrParoled(PACKAGE_1, USER_ID, assertFalse(mController.isAppIdleFilteredOrParoled(PACKAGE_1, USER_ID, mInjector.mElapsedRealtime, false)); setChargingState(controller, false); setChargingState(mController, false); mInjector.mElapsedRealtime = 2 * RARE_THRESHOLD + 2; controller.checkIdleStates(USER_ID); assertTrue(controller.isAppIdleFilteredOrParoled(PACKAGE_1, USER_ID, mController.checkIdleStates(USER_ID); assertTrue(mController.isAppIdleFilteredOrParoled(PACKAGE_1, USER_ID, mInjector.mElapsedRealtime, false)); setChargingState(controller, true); assertFalse(controller.isAppIdleFilteredOrParoled(PACKAGE_1,USER_ID, setChargingState(mController, true); assertFalse(mController.isAppIdleFilteredOrParoled(PACKAGE_1,USER_ID, mInjector.mElapsedRealtime, false)); } Loading Loading @@ -282,112 +287,142 @@ public class AppStandbyControllerTests { @Test public void testBuckets() throws Exception { AppStandbyController controller = setupController(); assertTimeout(controller, 0, UsageStatsManager.STANDBY_BUCKET_NEVER); assertTimeout(mController, 0, STANDBY_BUCKET_NEVER); reportEvent(controller, USER_INTERACTION, 0); reportEvent(mController, USER_INTERACTION, 0); // ACTIVE bucket assertTimeout(controller, WORKING_SET_THRESHOLD - 1, STANDBY_BUCKET_ACTIVE); assertTimeout(mController, WORKING_SET_THRESHOLD - 1, STANDBY_BUCKET_ACTIVE); // WORKING_SET bucket assertTimeout(controller, WORKING_SET_THRESHOLD + 1, STANDBY_BUCKET_WORKING_SET); assertTimeout(mController, WORKING_SET_THRESHOLD + 1, STANDBY_BUCKET_WORKING_SET); // WORKING_SET bucket assertTimeout(controller, FREQUENT_THRESHOLD - 1, STANDBY_BUCKET_WORKING_SET); assertTimeout(mController, FREQUENT_THRESHOLD - 1, STANDBY_BUCKET_WORKING_SET); // FREQUENT bucket assertTimeout(controller, FREQUENT_THRESHOLD + 1, STANDBY_BUCKET_FREQUENT); assertTimeout(mController, FREQUENT_THRESHOLD + 1, STANDBY_BUCKET_FREQUENT); // RARE bucket assertTimeout(controller, RARE_THRESHOLD + 1, STANDBY_BUCKET_RARE); assertTimeout(mController, RARE_THRESHOLD + 1, STANDBY_BUCKET_RARE); reportEvent(controller, USER_INTERACTION, RARE_THRESHOLD + 1); reportEvent(mController, USER_INTERACTION, RARE_THRESHOLD + 1); assertTimeout(controller, RARE_THRESHOLD + 1, STANDBY_BUCKET_ACTIVE); assertTimeout(mController, RARE_THRESHOLD + 1, STANDBY_BUCKET_ACTIVE); // RARE bucket assertTimeout(controller, RARE_THRESHOLD * 2 + 2, STANDBY_BUCKET_RARE); assertTimeout(mController, RARE_THRESHOLD * 2 + 2, STANDBY_BUCKET_RARE); } @Test public void testScreenTimeAndBuckets() throws Exception { AppStandbyController controller = setupController(); mInjector.setDisplayOn(false); assertTimeout(controller, 0, UsageStatsManager.STANDBY_BUCKET_NEVER); assertTimeout(mController, 0, STANDBY_BUCKET_NEVER); reportEvent(controller, USER_INTERACTION, 0); reportEvent(mController, USER_INTERACTION, 0); // ACTIVE bucket assertTimeout(controller, WORKING_SET_THRESHOLD - 1, STANDBY_BUCKET_ACTIVE); assertTimeout(mController, WORKING_SET_THRESHOLD - 1, STANDBY_BUCKET_ACTIVE); // WORKING_SET bucket assertTimeout(controller, WORKING_SET_THRESHOLD + 1, STANDBY_BUCKET_WORKING_SET); assertTimeout(mController, WORKING_SET_THRESHOLD + 1, STANDBY_BUCKET_WORKING_SET); // RARE bucket, should fail because the screen wasn't ON. mInjector.mElapsedRealtime = RARE_THRESHOLD + 1; controller.checkIdleStates(USER_ID); assertNotEquals(STANDBY_BUCKET_RARE, getStandbyBucket(controller)); mController.checkIdleStates(USER_ID); assertNotEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController)); mInjector.setDisplayOn(true); assertTimeout(controller, RARE_THRESHOLD * 2 + 2, STANDBY_BUCKET_RARE); assertTimeout(mController, RARE_THRESHOLD * 2 + 2, STANDBY_BUCKET_RARE); } @Test public void testForcedIdle() throws Exception { AppStandbyController controller = setupController(); setChargingState(controller, false); setChargingState(mController, false); controller.forceIdleState(PACKAGE_1, USER_ID, true); assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(controller)); assertTrue(controller.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0)); mController.forceIdleState(PACKAGE_1, USER_ID, true); assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController)); assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0)); controller.forceIdleState(PACKAGE_1, USER_ID, false); assertEquals(STANDBY_BUCKET_ACTIVE, controller.getAppStandbyBucket(PACKAGE_1, USER_ID, 0, mController.forceIdleState(PACKAGE_1, USER_ID, false); assertEquals(STANDBY_BUCKET_ACTIVE, mController.getAppStandbyBucket(PACKAGE_1, USER_ID, 0, true)); assertFalse(controller.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0)); assertFalse(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0)); } @Test public void testNotificationEvent() throws Exception { AppStandbyController controller = setupController(); setChargingState(controller, false); setChargingState(mController, false); reportEvent(controller, USER_INTERACTION, 0); assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(controller)); reportEvent(mController, USER_INTERACTION, 0); assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController)); mInjector.mElapsedRealtime = 1; reportEvent(controller, NOTIFICATION_SEEN, mInjector.mElapsedRealtime); assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(controller)); reportEvent(mController, NOTIFICATION_SEEN, mInjector.mElapsedRealtime); assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController)); controller.forceIdleState(PACKAGE_1, USER_ID, true); reportEvent(controller, NOTIFICATION_SEEN, mInjector.mElapsedRealtime); assertEquals(STANDBY_BUCKET_WORKING_SET, getStandbyBucket(controller)); mController.forceIdleState(PACKAGE_1, USER_ID, true); reportEvent(mController, NOTIFICATION_SEEN, mInjector.mElapsedRealtime); assertEquals(STANDBY_BUCKET_WORKING_SET, getStandbyBucket(mController)); } @Test public void testPredictionTimedout() throws Exception { AppStandbyController controller = setupController(); setChargingState(controller, false); controller.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE, REASON_PREDICTED + "CTS", 1 * HOUR_MS); setChargingState(mController, false); // Set it to timeout or usage, so that prediction can override it mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE, REASON_TIMEOUT, 1 * HOUR_MS); assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController)); mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE, REASON_PREDICTED + ":CTS", 1 * HOUR_MS); assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController)); // Fast forward 12 hours mInjector.mElapsedRealtime += WORKING_SET_THRESHOLD; controller.checkIdleStates(USER_ID); mController.checkIdleStates(USER_ID); // Should still be in predicted bucket, since prediction timeout is 1 day since prediction assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(controller)); assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController)); // Fast forward two more hours mInjector.mElapsedRealtime += 2 * HOUR_MS; controller.checkIdleStates(USER_ID); mController.checkIdleStates(USER_ID); // Should have now applied prediction timeout assertEquals(STANDBY_BUCKET_WORKING_SET, getStandbyBucket(controller)); assertEquals(STANDBY_BUCKET_WORKING_SET, getStandbyBucket(mController)); // Fast forward RARE bucket mInjector.mElapsedRealtime += RARE_THRESHOLD; controller.checkIdleStates(USER_ID); mController.checkIdleStates(USER_ID); // Should continue to apply prediction timeout assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(controller)); assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController)); } @Test public void testOverrides() throws Exception { setChargingState(mController, false); // Can force to NEVER mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_NEVER, REASON_FORCED, 1 * HOUR_MS); assertEquals(STANDBY_BUCKET_NEVER, getStandbyBucket(mController)); // Prediction can't override FORCED reason mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT, REASON_FORCED, 1 * HOUR_MS); mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_WORKING_SET, REASON_PREDICTED, 1 * HOUR_MS); assertEquals(STANDBY_BUCKET_FREQUENT, getStandbyBucket(mController)); // Prediction can't override NEVER mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_NEVER, REASON_DEFAULT, 2 * HOUR_MS); mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE, REASON_PREDICTED, 2 * HOUR_MS); assertEquals(STANDBY_BUCKET_NEVER, getStandbyBucket(mController)); // Prediction can't set to NEVER mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE, REASON_USAGE, 2 * HOUR_MS); mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_NEVER, REASON_PREDICTED, 2 * HOUR_MS); assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController)); } } services/usage/java/com/android/server/usage/AppStandbyController.java +25 −7 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import static android.app.usage.UsageStatsManager.REASON_USAGE; import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_ACTIVE; import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_EXEMPTED; import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_FREQUENT; import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_NEVER; import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RARE; import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_WORKING_SET; Loading Loading @@ -133,7 +134,7 @@ public class AppStandbyController { @GuardedBy("mAppIdleLock") private AppIdleHistory mAppIdleHistory; @GuardedBy("mAppIdleLock") @GuardedBy("mPackageAccessListeners") private ArrayList<AppIdleStateChangeListener> mPackageAccessListeners = new ArrayList<>(); Loading Loading @@ -592,7 +593,7 @@ public class AppStandbyController { } void addListener(AppIdleStateChangeListener listener) { synchronized (mAppIdleLock) { synchronized (mPackageAccessListeners) { if (!mPackageAccessListeners.contains(listener)) { mPackageAccessListeners.add(listener); } Loading @@ -600,7 +601,7 @@ public class AppStandbyController { } void removeListener(AppIdleStateChangeListener listener) { synchronized (mAppIdleLock) { synchronized (mPackageAccessListeners) { mPackageAccessListeners.remove(listener); } } Loading Loading @@ -789,6 +790,19 @@ public class AppStandbyController { void setAppStandbyBucket(String packageName, int userId, @StandbyBuckets int newBucket, String reason, long elapsedRealtime) { synchronized (mAppIdleLock) { AppIdleHistory.AppUsageHistory app = mAppIdleHistory.getAppUsageHistory(packageName, userId, elapsedRealtime); boolean predicted = reason != null && reason.startsWith(REASON_PREDICTED); // Don't allow changing bucket if higher than ACTIVE if (app.currentBucket < STANDBY_BUCKET_ACTIVE) return; // Don't allow prediction to change from or to NEVER if ((app.currentBucket == STANDBY_BUCKET_NEVER || newBucket == STANDBY_BUCKET_NEVER) && predicted) { return; } // If the bucket was forced, don't allow prediction to override if (app.bucketingReason.equals(REASON_FORCED) && predicted) return; mAppIdleHistory.setAppStandbyBucket(packageName, userId, elapsedRealtime, newBucket, reason); } Loading Loading @@ -852,17 +866,21 @@ public class AppStandbyController { void informListeners(String packageName, int userId, int bucket) { final boolean idle = bucket >= STANDBY_BUCKET_RARE; synchronized (mPackageAccessListeners) { for (AppIdleStateChangeListener listener : mPackageAccessListeners) { listener.onAppIdleStateChanged(packageName, userId, idle, bucket); } } } void informParoleStateChanged() { final boolean paroled = isParoledOrCharging(); synchronized (mPackageAccessListeners) { for (AppIdleStateChangeListener listener : mPackageAccessListeners) { listener.onParoleStateChanged(paroled); } } } void flushToDisk(int userId) { synchronized (mAppIdleLock) { Loading services/usage/java/com/android/server/usage/UsageStatsService.java +10 −4 Original line number Diff line number Diff line Loading @@ -728,6 +728,10 @@ public class UsageStatsService extends SystemService implements } catch (RemoteException re) { throw re.rethrowFromSystemServer(); } final boolean shellCaller = callingUid == 0 || callingUid == Process.SHELL_UID; final String reason = shellCaller ? UsageStatsManager.REASON_FORCED : UsageStatsManager.REASON_PREDICTED + ":" + callingUid; final long token = Binder.clearCallingIdentity(); try { // Caller cannot set their own standby state Loading @@ -735,8 +739,7 @@ public class UsageStatsService extends SystemService implements PackageManager.MATCH_ANY_USER, userId) == callingUid) { throw new IllegalArgumentException("Cannot set your own standby bucket"); } mAppStandby.setAppStandbyBucket(packageName, userId, bucket, UsageStatsManager.REASON_PREDICTED + ":" + callingUid, mAppStandby.setAppStandbyBucket(packageName, userId, bucket, reason, SystemClock.elapsedRealtime()); } finally { Binder.restoreCallingIdentity(token); Loading Loading @@ -779,6 +782,10 @@ public class UsageStatsService extends SystemService implements } catch (RemoteException re) { throw re.rethrowFromSystemServer(); } final boolean shellCaller = callingUid == 0 || callingUid == Process.SHELL_UID; final String reason = shellCaller ? UsageStatsManager.REASON_FORCED : UsageStatsManager.REASON_PREDICTED + ":" + callingUid; final long token = Binder.clearCallingIdentity(); try { final long elapsedRealtime = SystemClock.elapsedRealtime(); Loading @@ -796,8 +803,7 @@ public class UsageStatsService extends SystemService implements PackageManager.MATCH_ANY_USER, userId) == callingUid) { throw new IllegalArgumentException("Cannot set your own standby bucket"); } mAppStandby.setAppStandbyBucket(packageName, userId, bucket, UsageStatsManager.REASON_PREDICTED + ":" + callingUid, mAppStandby.setAppStandbyBucket(packageName, userId, bucket, reason, elapsedRealtime); } } finally { Loading Loading
services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java +91 −56 Original line number Diff line number Diff line Loading @@ -18,9 +18,14 @@ package com.android.server.usage; import static android.app.usage.UsageEvents.Event.NOTIFICATION_SEEN; import static android.app.usage.UsageEvents.Event.USER_INTERACTION; import static android.app.usage.UsageStatsManager.REASON_DEFAULT; import static android.app.usage.UsageStatsManager.REASON_FORCED; import static android.app.usage.UsageStatsManager.REASON_PREDICTED; import static android.app.usage.UsageStatsManager.REASON_TIMEOUT; import static android.app.usage.UsageStatsManager.REASON_USAGE; import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_ACTIVE; import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_FREQUENT; import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_NEVER; import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RARE; import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_WORKING_SET; Loading Loading @@ -79,6 +84,7 @@ public class AppStandbyControllerTests { private static final long RARE_THRESHOLD = 48 * HOUR_MS; private MyInjector mInjector; private AppStandbyController mController; static class MyContextWrapper extends ContextWrapper { PackageManager mockPm = mock(PackageManager.class); Loading Loading @@ -237,24 +243,23 @@ public class AppStandbyControllerTests { public void setUp() throws Exception { MyContextWrapper myContext = new MyContextWrapper(InstrumentationRegistry.getContext()); mInjector = new MyInjector(myContext, Looper.getMainLooper()); mController = setupController(); } @Test public void testCharging() throws Exception { AppStandbyController controller = setupController(); setChargingState(controller, true); setChargingState(mController, true); mInjector.mElapsedRealtime = RARE_THRESHOLD + 1; assertFalse(controller.isAppIdleFilteredOrParoled(PACKAGE_1, USER_ID, assertFalse(mController.isAppIdleFilteredOrParoled(PACKAGE_1, USER_ID, mInjector.mElapsedRealtime, false)); setChargingState(controller, false); setChargingState(mController, false); mInjector.mElapsedRealtime = 2 * RARE_THRESHOLD + 2; controller.checkIdleStates(USER_ID); assertTrue(controller.isAppIdleFilteredOrParoled(PACKAGE_1, USER_ID, mController.checkIdleStates(USER_ID); assertTrue(mController.isAppIdleFilteredOrParoled(PACKAGE_1, USER_ID, mInjector.mElapsedRealtime, false)); setChargingState(controller, true); assertFalse(controller.isAppIdleFilteredOrParoled(PACKAGE_1,USER_ID, setChargingState(mController, true); assertFalse(mController.isAppIdleFilteredOrParoled(PACKAGE_1,USER_ID, mInjector.mElapsedRealtime, false)); } Loading Loading @@ -282,112 +287,142 @@ public class AppStandbyControllerTests { @Test public void testBuckets() throws Exception { AppStandbyController controller = setupController(); assertTimeout(controller, 0, UsageStatsManager.STANDBY_BUCKET_NEVER); assertTimeout(mController, 0, STANDBY_BUCKET_NEVER); reportEvent(controller, USER_INTERACTION, 0); reportEvent(mController, USER_INTERACTION, 0); // ACTIVE bucket assertTimeout(controller, WORKING_SET_THRESHOLD - 1, STANDBY_BUCKET_ACTIVE); assertTimeout(mController, WORKING_SET_THRESHOLD - 1, STANDBY_BUCKET_ACTIVE); // WORKING_SET bucket assertTimeout(controller, WORKING_SET_THRESHOLD + 1, STANDBY_BUCKET_WORKING_SET); assertTimeout(mController, WORKING_SET_THRESHOLD + 1, STANDBY_BUCKET_WORKING_SET); // WORKING_SET bucket assertTimeout(controller, FREQUENT_THRESHOLD - 1, STANDBY_BUCKET_WORKING_SET); assertTimeout(mController, FREQUENT_THRESHOLD - 1, STANDBY_BUCKET_WORKING_SET); // FREQUENT bucket assertTimeout(controller, FREQUENT_THRESHOLD + 1, STANDBY_BUCKET_FREQUENT); assertTimeout(mController, FREQUENT_THRESHOLD + 1, STANDBY_BUCKET_FREQUENT); // RARE bucket assertTimeout(controller, RARE_THRESHOLD + 1, STANDBY_BUCKET_RARE); assertTimeout(mController, RARE_THRESHOLD + 1, STANDBY_BUCKET_RARE); reportEvent(controller, USER_INTERACTION, RARE_THRESHOLD + 1); reportEvent(mController, USER_INTERACTION, RARE_THRESHOLD + 1); assertTimeout(controller, RARE_THRESHOLD + 1, STANDBY_BUCKET_ACTIVE); assertTimeout(mController, RARE_THRESHOLD + 1, STANDBY_BUCKET_ACTIVE); // RARE bucket assertTimeout(controller, RARE_THRESHOLD * 2 + 2, STANDBY_BUCKET_RARE); assertTimeout(mController, RARE_THRESHOLD * 2 + 2, STANDBY_BUCKET_RARE); } @Test public void testScreenTimeAndBuckets() throws Exception { AppStandbyController controller = setupController(); mInjector.setDisplayOn(false); assertTimeout(controller, 0, UsageStatsManager.STANDBY_BUCKET_NEVER); assertTimeout(mController, 0, STANDBY_BUCKET_NEVER); reportEvent(controller, USER_INTERACTION, 0); reportEvent(mController, USER_INTERACTION, 0); // ACTIVE bucket assertTimeout(controller, WORKING_SET_THRESHOLD - 1, STANDBY_BUCKET_ACTIVE); assertTimeout(mController, WORKING_SET_THRESHOLD - 1, STANDBY_BUCKET_ACTIVE); // WORKING_SET bucket assertTimeout(controller, WORKING_SET_THRESHOLD + 1, STANDBY_BUCKET_WORKING_SET); assertTimeout(mController, WORKING_SET_THRESHOLD + 1, STANDBY_BUCKET_WORKING_SET); // RARE bucket, should fail because the screen wasn't ON. mInjector.mElapsedRealtime = RARE_THRESHOLD + 1; controller.checkIdleStates(USER_ID); assertNotEquals(STANDBY_BUCKET_RARE, getStandbyBucket(controller)); mController.checkIdleStates(USER_ID); assertNotEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController)); mInjector.setDisplayOn(true); assertTimeout(controller, RARE_THRESHOLD * 2 + 2, STANDBY_BUCKET_RARE); assertTimeout(mController, RARE_THRESHOLD * 2 + 2, STANDBY_BUCKET_RARE); } @Test public void testForcedIdle() throws Exception { AppStandbyController controller = setupController(); setChargingState(controller, false); setChargingState(mController, false); controller.forceIdleState(PACKAGE_1, USER_ID, true); assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(controller)); assertTrue(controller.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0)); mController.forceIdleState(PACKAGE_1, USER_ID, true); assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController)); assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0)); controller.forceIdleState(PACKAGE_1, USER_ID, false); assertEquals(STANDBY_BUCKET_ACTIVE, controller.getAppStandbyBucket(PACKAGE_1, USER_ID, 0, mController.forceIdleState(PACKAGE_1, USER_ID, false); assertEquals(STANDBY_BUCKET_ACTIVE, mController.getAppStandbyBucket(PACKAGE_1, USER_ID, 0, true)); assertFalse(controller.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0)); assertFalse(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0)); } @Test public void testNotificationEvent() throws Exception { AppStandbyController controller = setupController(); setChargingState(controller, false); setChargingState(mController, false); reportEvent(controller, USER_INTERACTION, 0); assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(controller)); reportEvent(mController, USER_INTERACTION, 0); assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController)); mInjector.mElapsedRealtime = 1; reportEvent(controller, NOTIFICATION_SEEN, mInjector.mElapsedRealtime); assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(controller)); reportEvent(mController, NOTIFICATION_SEEN, mInjector.mElapsedRealtime); assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController)); controller.forceIdleState(PACKAGE_1, USER_ID, true); reportEvent(controller, NOTIFICATION_SEEN, mInjector.mElapsedRealtime); assertEquals(STANDBY_BUCKET_WORKING_SET, getStandbyBucket(controller)); mController.forceIdleState(PACKAGE_1, USER_ID, true); reportEvent(mController, NOTIFICATION_SEEN, mInjector.mElapsedRealtime); assertEquals(STANDBY_BUCKET_WORKING_SET, getStandbyBucket(mController)); } @Test public void testPredictionTimedout() throws Exception { AppStandbyController controller = setupController(); setChargingState(controller, false); controller.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE, REASON_PREDICTED + "CTS", 1 * HOUR_MS); setChargingState(mController, false); // Set it to timeout or usage, so that prediction can override it mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE, REASON_TIMEOUT, 1 * HOUR_MS); assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController)); mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE, REASON_PREDICTED + ":CTS", 1 * HOUR_MS); assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController)); // Fast forward 12 hours mInjector.mElapsedRealtime += WORKING_SET_THRESHOLD; controller.checkIdleStates(USER_ID); mController.checkIdleStates(USER_ID); // Should still be in predicted bucket, since prediction timeout is 1 day since prediction assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(controller)); assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController)); // Fast forward two more hours mInjector.mElapsedRealtime += 2 * HOUR_MS; controller.checkIdleStates(USER_ID); mController.checkIdleStates(USER_ID); // Should have now applied prediction timeout assertEquals(STANDBY_BUCKET_WORKING_SET, getStandbyBucket(controller)); assertEquals(STANDBY_BUCKET_WORKING_SET, getStandbyBucket(mController)); // Fast forward RARE bucket mInjector.mElapsedRealtime += RARE_THRESHOLD; controller.checkIdleStates(USER_ID); mController.checkIdleStates(USER_ID); // Should continue to apply prediction timeout assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(controller)); assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController)); } @Test public void testOverrides() throws Exception { setChargingState(mController, false); // Can force to NEVER mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_NEVER, REASON_FORCED, 1 * HOUR_MS); assertEquals(STANDBY_BUCKET_NEVER, getStandbyBucket(mController)); // Prediction can't override FORCED reason mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT, REASON_FORCED, 1 * HOUR_MS); mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_WORKING_SET, REASON_PREDICTED, 1 * HOUR_MS); assertEquals(STANDBY_BUCKET_FREQUENT, getStandbyBucket(mController)); // Prediction can't override NEVER mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_NEVER, REASON_DEFAULT, 2 * HOUR_MS); mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE, REASON_PREDICTED, 2 * HOUR_MS); assertEquals(STANDBY_BUCKET_NEVER, getStandbyBucket(mController)); // Prediction can't set to NEVER mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE, REASON_USAGE, 2 * HOUR_MS); mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_NEVER, REASON_PREDICTED, 2 * HOUR_MS); assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController)); } }
services/usage/java/com/android/server/usage/AppStandbyController.java +25 −7 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import static android.app.usage.UsageStatsManager.REASON_USAGE; import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_ACTIVE; import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_EXEMPTED; import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_FREQUENT; import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_NEVER; import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RARE; import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_WORKING_SET; Loading Loading @@ -133,7 +134,7 @@ public class AppStandbyController { @GuardedBy("mAppIdleLock") private AppIdleHistory mAppIdleHistory; @GuardedBy("mAppIdleLock") @GuardedBy("mPackageAccessListeners") private ArrayList<AppIdleStateChangeListener> mPackageAccessListeners = new ArrayList<>(); Loading Loading @@ -592,7 +593,7 @@ public class AppStandbyController { } void addListener(AppIdleStateChangeListener listener) { synchronized (mAppIdleLock) { synchronized (mPackageAccessListeners) { if (!mPackageAccessListeners.contains(listener)) { mPackageAccessListeners.add(listener); } Loading @@ -600,7 +601,7 @@ public class AppStandbyController { } void removeListener(AppIdleStateChangeListener listener) { synchronized (mAppIdleLock) { synchronized (mPackageAccessListeners) { mPackageAccessListeners.remove(listener); } } Loading Loading @@ -789,6 +790,19 @@ public class AppStandbyController { void setAppStandbyBucket(String packageName, int userId, @StandbyBuckets int newBucket, String reason, long elapsedRealtime) { synchronized (mAppIdleLock) { AppIdleHistory.AppUsageHistory app = mAppIdleHistory.getAppUsageHistory(packageName, userId, elapsedRealtime); boolean predicted = reason != null && reason.startsWith(REASON_PREDICTED); // Don't allow changing bucket if higher than ACTIVE if (app.currentBucket < STANDBY_BUCKET_ACTIVE) return; // Don't allow prediction to change from or to NEVER if ((app.currentBucket == STANDBY_BUCKET_NEVER || newBucket == STANDBY_BUCKET_NEVER) && predicted) { return; } // If the bucket was forced, don't allow prediction to override if (app.bucketingReason.equals(REASON_FORCED) && predicted) return; mAppIdleHistory.setAppStandbyBucket(packageName, userId, elapsedRealtime, newBucket, reason); } Loading Loading @@ -852,17 +866,21 @@ public class AppStandbyController { void informListeners(String packageName, int userId, int bucket) { final boolean idle = bucket >= STANDBY_BUCKET_RARE; synchronized (mPackageAccessListeners) { for (AppIdleStateChangeListener listener : mPackageAccessListeners) { listener.onAppIdleStateChanged(packageName, userId, idle, bucket); } } } void informParoleStateChanged() { final boolean paroled = isParoledOrCharging(); synchronized (mPackageAccessListeners) { for (AppIdleStateChangeListener listener : mPackageAccessListeners) { listener.onParoleStateChanged(paroled); } } } void flushToDisk(int userId) { synchronized (mAppIdleLock) { Loading
services/usage/java/com/android/server/usage/UsageStatsService.java +10 −4 Original line number Diff line number Diff line Loading @@ -728,6 +728,10 @@ public class UsageStatsService extends SystemService implements } catch (RemoteException re) { throw re.rethrowFromSystemServer(); } final boolean shellCaller = callingUid == 0 || callingUid == Process.SHELL_UID; final String reason = shellCaller ? UsageStatsManager.REASON_FORCED : UsageStatsManager.REASON_PREDICTED + ":" + callingUid; final long token = Binder.clearCallingIdentity(); try { // Caller cannot set their own standby state Loading @@ -735,8 +739,7 @@ public class UsageStatsService extends SystemService implements PackageManager.MATCH_ANY_USER, userId) == callingUid) { throw new IllegalArgumentException("Cannot set your own standby bucket"); } mAppStandby.setAppStandbyBucket(packageName, userId, bucket, UsageStatsManager.REASON_PREDICTED + ":" + callingUid, mAppStandby.setAppStandbyBucket(packageName, userId, bucket, reason, SystemClock.elapsedRealtime()); } finally { Binder.restoreCallingIdentity(token); Loading Loading @@ -779,6 +782,10 @@ public class UsageStatsService extends SystemService implements } catch (RemoteException re) { throw re.rethrowFromSystemServer(); } final boolean shellCaller = callingUid == 0 || callingUid == Process.SHELL_UID; final String reason = shellCaller ? UsageStatsManager.REASON_FORCED : UsageStatsManager.REASON_PREDICTED + ":" + callingUid; final long token = Binder.clearCallingIdentity(); try { final long elapsedRealtime = SystemClock.elapsedRealtime(); Loading @@ -796,8 +803,7 @@ public class UsageStatsService extends SystemService implements PackageManager.MATCH_ANY_USER, userId) == callingUid) { throw new IllegalArgumentException("Cannot set your own standby bucket"); } mAppStandby.setAppStandbyBucket(packageName, userId, bucket, UsageStatsManager.REASON_PREDICTED + ":" + callingUid, mAppStandby.setAppStandbyBucket(packageName, userId, bucket, reason, elapsedRealtime); } } finally { Loading