Merge "Prevents uninstalled packages from being added to the DB."
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 869f8fa0..caaa0bb 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
@@ -43,6 +43,7 @@
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
+import android.app.usage.AppStandbyInfo;
import android.app.usage.UsageEvents;
import android.app.usage.UsageStatsManagerInternal;
import android.appwidget.AppWidgetManager;
@@ -92,6 +93,8 @@
private static final int USER_ID = 0;
private static final int USER_ID2 = 10;
+ private static final String PACKAGE_UNKNOWN = "com.example.unknown";
+
private static final String ADMIN_PKG = "com.android.admin";
private static final String ADMIN_PKG2 = "com.android.admin2";
private static final String ADMIN_PKG3 = "com.android.admin3";
@@ -106,6 +109,9 @@
// Short STABLE_CHARGING_THRESHOLD for testing purposes
private static final long STABLE_CHARGING_THRESHOLD = 2000;
+ /** Mock variable used in {@link MyInjector#isPackageInstalled(String, int, int)} */
+ private static boolean isPackageInstalled = true;
+
private MyInjector mInjector;
private AppStandbyController mController;
@@ -183,6 +189,12 @@
}
@Override
+ boolean isPackageInstalled(String packageName, int flags, int userId) {
+ // Should always return true (default value) unless testing for an uninstalled app
+ return isPackageInstalled;
+ }
+
+ @Override
int[] getRunningUserIds() {
return new int[] {USER_ID};
}
@@ -403,30 +415,30 @@
false));
}
- private void reportEvent(AppStandbyController controller, int eventType,
- long elapsedTime) {
+ private void reportEvent(AppStandbyController controller, int eventType, long elapsedTime,
+ String packageName) {
// Back to ACTIVE on event
mInjector.mElapsedRealtime = elapsedTime;
UsageEvents.Event ev = new UsageEvents.Event();
- ev.mPackage = PACKAGE_1;
+ ev.mPackage = packageName;
ev.mEventType = eventType;
controller.reportEvent(ev, elapsedTime, USER_ID);
}
- private int getStandbyBucket(AppStandbyController controller) {
- return controller.getAppStandbyBucket(PACKAGE_1, USER_ID, mInjector.mElapsedRealtime,
+ private int getStandbyBucket(AppStandbyController controller, String packageName) {
+ return controller.getAppStandbyBucket(packageName, USER_ID, mInjector.mElapsedRealtime,
true);
}
private void assertBucket(int bucket) {
- assertEquals(bucket, getStandbyBucket(mController));
+ assertEquals(bucket, getStandbyBucket(mController, PACKAGE_1));
}
@Test
public void testBuckets() throws Exception {
assertTimeout(mController, 0, STANDBY_BUCKET_NEVER);
- reportEvent(mController, USER_INTERACTION, 0);
+ reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
// ACTIVE bucket
assertTimeout(mController, WORKING_SET_THRESHOLD - 1, STANDBY_BUCKET_ACTIVE);
@@ -443,7 +455,7 @@
// RARE bucket
assertTimeout(mController, RARE_THRESHOLD + 1, STANDBY_BUCKET_RARE);
- reportEvent(mController, USER_INTERACTION, RARE_THRESHOLD + 1);
+ reportEvent(mController, USER_INTERACTION, RARE_THRESHOLD + 1, PACKAGE_1);
assertTimeout(mController, RARE_THRESHOLD + 1, STANDBY_BUCKET_ACTIVE);
@@ -452,12 +464,48 @@
}
@Test
+ public void testSetAppStandbyBucket() throws Exception {
+ // For a known package, standby bucket should be set properly
+ reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
+ mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE,
+ REASON_MAIN_TIMEOUT, HOUR_MS);
+ assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1));
+
+ // For an unknown package, standby bucket should not be set, hence NEVER is returned
+ // Ensure the unknown package is not already in history by removing it
+ mController.clearAppIdleForPackage(PACKAGE_UNKNOWN, USER_ID);
+ isPackageInstalled = false; // Mock package is not installed
+ mController.setAppStandbyBucket(PACKAGE_UNKNOWN, USER_ID, STANDBY_BUCKET_ACTIVE,
+ REASON_MAIN_TIMEOUT, HOUR_MS);
+ isPackageInstalled = true; // Reset mocked variable for other tests
+ assertEquals(STANDBY_BUCKET_NEVER, getStandbyBucket(mController, PACKAGE_UNKNOWN));
+ }
+
+ @Test
+ public void testAppStandbyBucketOnInstallAndUninstall() throws Exception {
+ // On package install, standby bucket should be ACTIVE
+ reportEvent(mController, USER_INTERACTION, 0, PACKAGE_UNKNOWN);
+ assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_UNKNOWN));
+
+ // On uninstall, package should not exist in history and should return a NEVER bucket
+ mController.clearAppIdleForPackage(PACKAGE_UNKNOWN, USER_ID);
+ assertEquals(STANDBY_BUCKET_NEVER, getStandbyBucket(mController, PACKAGE_UNKNOWN));
+ // Ensure uninstalled app is not in history
+ List<AppStandbyInfo> buckets = mController.getAppStandbyBuckets(USER_ID);
+ for(AppStandbyInfo bucket : buckets) {
+ if (bucket.mPackageName.equals(PACKAGE_UNKNOWN)) {
+ fail("packageName found in app idle history after uninstall.");
+ }
+ }
+ }
+
+ @Test
public void testScreenTimeAndBuckets() throws Exception {
mInjector.setDisplayOn(false);
assertTimeout(mController, 0, STANDBY_BUCKET_NEVER);
- reportEvent(mController, USER_INTERACTION, 0);
+ reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
// ACTIVE bucket
assertTimeout(mController, WORKING_SET_THRESHOLD - 1, STANDBY_BUCKET_ACTIVE);
@@ -468,7 +516,7 @@
// RARE bucket, should fail because the screen wasn't ON.
mInjector.mElapsedRealtime = RARE_THRESHOLD + 1;
mController.checkIdleStates(USER_ID);
- assertNotEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController));
+ assertNotEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1));
mInjector.setDisplayOn(true);
assertTimeout(mController, RARE_THRESHOLD * 2 + 2, STANDBY_BUCKET_RARE);
@@ -477,7 +525,7 @@
@Test
public void testForcedIdle() throws Exception {
mController.forceIdleState(PACKAGE_1, USER_ID, true);
- assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController));
+ assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1));
assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0));
mController.forceIdleState(PACKAGE_1, USER_ID, false);
@@ -488,35 +536,35 @@
@Test
public void testNotificationEvent() throws Exception {
- reportEvent(mController, USER_INTERACTION, 0);
- assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController));
+ reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
+ assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1));
mInjector.mElapsedRealtime = 1;
- reportEvent(mController, NOTIFICATION_SEEN, mInjector.mElapsedRealtime);
- assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController));
+ reportEvent(mController, NOTIFICATION_SEEN, mInjector.mElapsedRealtime, PACKAGE_1);
+ assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1));
mController.forceIdleState(PACKAGE_1, USER_ID, true);
- reportEvent(mController, NOTIFICATION_SEEN, mInjector.mElapsedRealtime);
- assertEquals(STANDBY_BUCKET_WORKING_SET, getStandbyBucket(mController));
+ reportEvent(mController, NOTIFICATION_SEEN, mInjector.mElapsedRealtime, PACKAGE_1);
+ assertEquals(STANDBY_BUCKET_WORKING_SET, getStandbyBucket(mController, PACKAGE_1));
}
@Test
public void testSlicePinnedEvent() throws Exception {
- reportEvent(mController, USER_INTERACTION, 0);
- assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController));
+ reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
+ assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1));
mInjector.mElapsedRealtime = 1;
- reportEvent(mController, SLICE_PINNED, mInjector.mElapsedRealtime);
- assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController));
+ reportEvent(mController, SLICE_PINNED, mInjector.mElapsedRealtime, PACKAGE_1);
+ assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1));
mController.forceIdleState(PACKAGE_1, USER_ID, true);
- reportEvent(mController, SLICE_PINNED, mInjector.mElapsedRealtime);
- assertEquals(STANDBY_BUCKET_WORKING_SET, getStandbyBucket(mController));
+ reportEvent(mController, SLICE_PINNED, mInjector.mElapsedRealtime, PACKAGE_1);
+ assertEquals(STANDBY_BUCKET_WORKING_SET, getStandbyBucket(mController, PACKAGE_1));
}
@Test
public void testSlicePinnedPrivEvent() throws Exception {
mController.forceIdleState(PACKAGE_1, USER_ID, true);
- reportEvent(mController, SLICE_PINNED_PRIV, mInjector.mElapsedRealtime);
- assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController));
+ reportEvent(mController, SLICE_PINNED_PRIV, mInjector.mElapsedRealtime, PACKAGE_1);
+ assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1));
}
@Test
@@ -524,28 +572,28 @@
// Set it to timeout or usage, so that prediction can override it
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE,
REASON_MAIN_TIMEOUT, HOUR_MS);
- assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController));
+ assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1));
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE,
REASON_MAIN_PREDICTED, HOUR_MS);
- assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController));
+ assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1));
// Fast forward 12 hours
mInjector.mElapsedRealtime += WORKING_SET_THRESHOLD;
mController.checkIdleStates(USER_ID);
// Should still be in predicted bucket, since prediction timeout is 1 day since prediction
- assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController));
+ assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1));
// Fast forward two more hours
mInjector.mElapsedRealtime += 2 * HOUR_MS;
mController.checkIdleStates(USER_ID);
// Should have now applied prediction timeout
- assertEquals(STANDBY_BUCKET_WORKING_SET, getStandbyBucket(mController));
+ assertEquals(STANDBY_BUCKET_WORKING_SET, getStandbyBucket(mController, PACKAGE_1));
// Fast forward RARE bucket
mInjector.mElapsedRealtime += RARE_THRESHOLD;
mController.checkIdleStates(USER_ID);
// Should continue to apply prediction timeout
- assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController));
+ assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1));
}
@Test
@@ -553,33 +601,33 @@
// Can force to NEVER
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_NEVER,
REASON_MAIN_FORCED, 1 * HOUR_MS);
- assertEquals(STANDBY_BUCKET_NEVER, getStandbyBucket(mController));
+ assertEquals(STANDBY_BUCKET_NEVER, getStandbyBucket(mController, PACKAGE_1));
// Prediction can't override FORCED reason
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
REASON_MAIN_FORCED, 1 * HOUR_MS);
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_WORKING_SET,
REASON_MAIN_PREDICTED, 1 * HOUR_MS);
- assertEquals(STANDBY_BUCKET_FREQUENT, getStandbyBucket(mController));
+ assertEquals(STANDBY_BUCKET_FREQUENT, getStandbyBucket(mController, PACKAGE_1));
// Prediction can't override NEVER
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_NEVER,
REASON_MAIN_DEFAULT, 2 * HOUR_MS);
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE,
REASON_MAIN_PREDICTED, 2 * HOUR_MS);
- assertEquals(STANDBY_BUCKET_NEVER, getStandbyBucket(mController));
+ assertEquals(STANDBY_BUCKET_NEVER, getStandbyBucket(mController, PACKAGE_1));
// Prediction can't set to NEVER
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE,
REASON_MAIN_USAGE, 2 * HOUR_MS);
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_NEVER,
REASON_MAIN_PREDICTED, 2 * HOUR_MS);
- assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController));
+ assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1));
}
@Test
public void testTimeout() throws Exception {
- reportEvent(mController, USER_INTERACTION, 0);
+ reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
assertBucket(STANDBY_BUCKET_ACTIVE);
mInjector.mElapsedRealtime = 2000;
@@ -601,10 +649,10 @@
@Test
public void testCascadingTimeouts() throws Exception {
- reportEvent(mController, USER_INTERACTION, 0);
+ reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
assertBucket(STANDBY_BUCKET_ACTIVE);
- reportEvent(mController, NOTIFICATION_SEEN, 1000);
+ reportEvent(mController, NOTIFICATION_SEEN, 1000, PACKAGE_1);
assertBucket(STANDBY_BUCKET_ACTIVE);
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_WORKING_SET,
@@ -622,14 +670,15 @@
@Test
public void testOverlappingTimeouts() throws Exception {
- reportEvent(mController, USER_INTERACTION, 0);
+ reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
assertBucket(STANDBY_BUCKET_ACTIVE);
- reportEvent(mController, NOTIFICATION_SEEN, 1000);
+ reportEvent(mController, NOTIFICATION_SEEN, 1000, PACKAGE_1);
assertBucket(STANDBY_BUCKET_ACTIVE);
// Overlapping USER_INTERACTION before previous one times out
- reportEvent(mController, USER_INTERACTION, mController.mStrongUsageTimeoutMillis - 1000);
+ reportEvent(mController, USER_INTERACTION, mController.mStrongUsageTimeoutMillis - 1000,
+ PACKAGE_1);
assertBucket(STANDBY_BUCKET_ACTIVE);
// Still in ACTIVE after first USER_INTERACTION times out
@@ -654,14 +703,14 @@
public void testSystemInteractionTimeout() throws Exception {
setChargingState(mController, false);
- reportEvent(mController, USER_INTERACTION, 0);
+ reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
// Fast forward to RARE
mInjector.mElapsedRealtime = RARE_THRESHOLD + 100;
mController.checkIdleStates(USER_ID);
assertBucket(STANDBY_BUCKET_RARE);
// Trigger a SYSTEM_INTERACTION and verify bucket
- reportEvent(mController, SYSTEM_INTERACTION, mInjector.mElapsedRealtime);
+ reportEvent(mController, SYSTEM_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
assertBucket(STANDBY_BUCKET_ACTIVE);
// Verify it's still in ACTIVE close to end of timeout
@@ -677,11 +726,11 @@
@Test
public void testPredictionNotOverridden() throws Exception {
- reportEvent(mController, USER_INTERACTION, 0);
+ reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
assertBucket(STANDBY_BUCKET_ACTIVE);
mInjector.mElapsedRealtime = WORKING_SET_THRESHOLD - 1000;
- reportEvent(mController, NOTIFICATION_SEEN, mInjector.mElapsedRealtime);
+ reportEvent(mController, NOTIFICATION_SEEN, mInjector.mElapsedRealtime, PACKAGE_1);
assertBucket(STANDBY_BUCKET_ACTIVE);
// Falls back to WORKING_SET
@@ -703,7 +752,7 @@
@Test
public void testPredictionStrikesBack() throws Exception {
- reportEvent(mController, USER_INTERACTION, 0);
+ reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
assertBucket(STANDBY_BUCKET_ACTIVE);
// Predict to FREQUENT
@@ -714,7 +763,7 @@
// Add a short timeout event
mInjector.mElapsedRealtime += 1000;
- reportEvent(mController, SYSTEM_INTERACTION, mInjector.mElapsedRealtime);
+ reportEvent(mController, SYSTEM_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
assertBucket(STANDBY_BUCKET_ACTIVE);
mInjector.mElapsedRealtime += 1000;
mController.checkIdleStates(USER_ID);
diff --git a/services/usage/java/com/android/server/usage/AppIdleHistory.java b/services/usage/java/com/android/server/usage/AppIdleHistory.java
index 4e99732..bc54a5d 100644
--- a/services/usage/java/com/android/server/usage/AppIdleHistory.java
+++ b/services/usage/java/com/android/server/usage/AppIdleHistory.java
@@ -320,14 +320,7 @@
ArrayMap<String, AppUsageHistory> userHistory = getUserHistory(userId);
AppUsageHistory appUsageHistory =
getPackageHistory(userHistory, packageName, elapsedRealtime, true);
- if (appUsageHistory == null) {
- return false; // Default to not idle
- } else {
- return appUsageHistory.currentBucket >= STANDBY_BUCKET_RARE;
- // Whether or not it's passed will now be externally calculated and the
- // bucket will be pushed to the history using setAppStandbyBucket()
- //return hasPassedThresholds(appUsageHistory, elapsedRealtime);
- }
+ return appUsageHistory.currentBucket >= STANDBY_BUCKET_RARE;
}
public AppUsageHistory getAppUsageHistory(String packageName, int userId,
@@ -404,17 +397,19 @@
public long getTimeSinceLastJobRun(String packageName, int userId, long elapsedRealtime) {
ArrayMap<String, AppUsageHistory> userHistory = getUserHistory(userId);
AppUsageHistory appUsageHistory =
- getPackageHistory(userHistory, packageName, elapsedRealtime, true);
+ getPackageHistory(userHistory, packageName, elapsedRealtime, false);
// Don't adjust the default, else it'll wrap around to a positive value
- if (appUsageHistory.lastJobRunTime == Long.MIN_VALUE) return Long.MAX_VALUE;
+ if (appUsageHistory == null || appUsageHistory.lastJobRunTime == Long.MIN_VALUE) {
+ return Long.MAX_VALUE;
+ }
return getElapsedTime(elapsedRealtime) - appUsageHistory.lastJobRunTime;
}
public int getAppStandbyBucket(String packageName, int userId, long elapsedRealtime) {
ArrayMap<String, AppUsageHistory> userHistory = getUserHistory(userId);
AppUsageHistory appUsageHistory =
- getPackageHistory(userHistory, packageName, elapsedRealtime, true);
- return appUsageHistory.currentBucket;
+ getPackageHistory(userHistory, packageName, elapsedRealtime, false);
+ return appUsageHistory == null ? STANDBY_BUCKET_NEVER : appUsageHistory.currentBucket;
}
public ArrayList<AppStandbyInfo> getAppStandbyBuckets(int userId, boolean appIdleEnabled) {
diff --git a/services/usage/java/com/android/server/usage/AppStandbyController.java b/services/usage/java/com/android/server/usage/AppStandbyController.java
index 02ad3a8..6a74564 100644
--- a/services/usage/java/com/android/server/usage/AppStandbyController.java
+++ b/services/usage/java/com/android/server/usage/AppStandbyController.java
@@ -1161,6 +1161,10 @@
void setAppStandbyBucket(String packageName, int userId, @StandbyBuckets int newBucket,
int reason, long elapsedRealtime, boolean resetTimeout) {
synchronized (mAppIdleLock) {
+ // If the package is not installed, don't allow the bucket to be set.
+ if (!mInjector.isPackageInstalled(packageName, 0, userId)) {
+ return;
+ }
AppIdleHistory.AppUsageHistory app = mAppIdleHistory.getAppUsageHistory(packageName,
userId, elapsedRealtime);
boolean predicted = (reason & REASON_MAIN_MASK) == REASON_MAIN_PREDICTED;
@@ -1594,6 +1598,10 @@
return mPackageManagerInternal.isPackageEphemeral(userId, packageName);
}
+ boolean isPackageInstalled(String packageName, int flags, int userId) {
+ return mPackageManagerInternal.getPackageUid(packageName, flags, userId) >= 0;
+ }
+
int[] getRunningUserIds() throws RemoteException {
return ActivityManager.getService().getRunningUserIds();
}