summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Amith Yamasani <yamasani@google.com> 2017-12-13 11:52:10 -0800
committer Amith Yamasani <yamasani@google.com> 2017-12-14 20:21:32 +0000
commit9388519d5e66a84485f8951242b9756e586a85ac (patch)
tree70d7c04f839fa63994d09754bcf57677adf8c91d
parentff38f236b55b51a9f8e03b909f4791ccca329c48 (diff)
Don't allow certain bucket overrides
Don't allow EXEMPT to be overridden Differentiate between shell and other callers who set buckets. Don't allow forced to be modified by bucketeer. Don't allow bucketeer to modify NEVER bucket. Fix a locking issue in listeners list. Don't use the primary lock when calling out to listeners. Fixes: 70622791 Fixes: 70622338 Test: atest FrameworksServicesTests:AppIdleHistoryTests atest FrameworksServicesTests:AppStandbyControllerTests atest CtsAppUsageHostTestCases Change-Id: I22309478b947d6461235f5a77e08c7be86309e4b
-rw-r--r--services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java147
-rw-r--r--services/usage/java/com/android/server/usage/AppStandbyController.java32
-rw-r--r--services/usage/java/com/android/server/usage/UsageStatsService.java14
3 files changed, 126 insertions, 67 deletions
diff --git a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
index 86ce90c03ae4..b792d821ae93 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
@@ -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(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));
}
}
diff --git a/services/usage/java/com/android/server/usage/AppStandbyController.java b/services/usage/java/com/android/server/usage/AppStandbyController.java
index 46efbd059d52..cc0259ddaa2b 100644
--- a/services/usage/java/com/android/server/usage/AppStandbyController.java
+++ b/services/usage/java/com/android/server/usage/AppStandbyController.java
@@ -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);
+ }
}
}
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 15284d5e3dec..07c860b54413 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -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 {