Merge "Don't allow certain bucket overrides"

This commit is contained in:
TreeHugger Robot
2017-12-15 00:46:24 +00:00
committed by Android (Google) Code Review
3 changed files with 126 additions and 67 deletions

View File

@@ -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;
@@ -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);
@@ -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));
}
@@ -282,112 +287,142 @@ public class AppStandbyControllerTests {
@Test
public void testBuckets() throws Exception {
AppStandbyController controller = setupController();
assertTimeout(mController, 0, STANDBY_BUCKET_NEVER);
assertTimeout(controller, 0, UsageStatsManager.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));
}
}

View File

@@ -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;
@@ -133,7 +134,7 @@ public class AppStandbyController {
@GuardedBy("mAppIdleLock")
private AppIdleHistory mAppIdleHistory;
@GuardedBy("mAppIdleLock")
@GuardedBy("mPackageAccessListeners")
private ArrayList<AppIdleStateChangeListener>
mPackageAccessListeners = new ArrayList<>();
@@ -592,7 +593,7 @@ public class AppStandbyController {
}
void addListener(AppIdleStateChangeListener listener) {
synchronized (mAppIdleLock) {
synchronized (mPackageAccessListeners) {
if (!mPackageAccessListeners.contains(listener)) {
mPackageAccessListeners.add(listener);
}
@@ -600,7 +601,7 @@ public class AppStandbyController {
}
void removeListener(AppIdleStateChangeListener listener) {
synchronized (mAppIdleLock) {
synchronized (mPackageAccessListeners) {
mPackageAccessListeners.remove(listener);
}
}
@@ -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);
}
@@ -852,15 +866,19 @@ public class AppStandbyController {
void informListeners(String packageName, int userId, int bucket) {
final boolean idle = bucket >= STANDBY_BUCKET_RARE;
for (AppIdleStateChangeListener listener : mPackageAccessListeners) {
listener.onAppIdleStateChanged(packageName, userId, idle, bucket);
synchronized (mPackageAccessListeners) {
for (AppIdleStateChangeListener listener : mPackageAccessListeners) {
listener.onAppIdleStateChanged(packageName, userId, idle, bucket);
}
}
}
void informParoleStateChanged() {
final boolean paroled = isParoledOrCharging();
for (AppIdleStateChangeListener listener : mPackageAccessListeners) {
listener.onParoleStateChanged(paroled);
synchronized (mPackageAccessListeners) {
for (AppIdleStateChangeListener listener : mPackageAccessListeners) {
listener.onParoleStateChanged(paroled);
}
}
}

View File

@@ -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
@@ -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);
@@ -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();
@@ -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 {