diff options
7 files changed, 78 insertions, 52 deletions
diff --git a/core/java/android/app/usage/UsageStatsManagerInternal.java b/core/java/android/app/usage/UsageStatsManagerInternal.java index dbaace2f0ac9..29e7439f69e2 100644 --- a/core/java/android/app/usage/UsageStatsManagerInternal.java +++ b/core/java/android/app/usage/UsageStatsManagerInternal.java @@ -118,7 +118,15 @@ public abstract class UsageStatsManagerInternal { AppIdleStateChangeListener listener); public static abstract class AppIdleStateChangeListener { - public abstract void onAppIdleStateChanged(String packageName, int userId, boolean idle); + + /** Callback to inform listeners that the idle state has changed to a new bucket. */ + public abstract void onAppIdleStateChanged(String packageName, int userId, boolean idle, + int bucket); + + /** + * Callback to inform listeners that the parole state has changed. This means apps are + * allowed to do work even if they're idle or in a low bucket. + */ public abstract void onParoleStateChanged(boolean isParoleOn); } diff --git a/services/core/java/com/android/server/job/controllers/AppIdleController.java b/services/core/java/com/android/server/job/controllers/AppIdleController.java index 39f2a96b30e3..caa8522089c6 100644 --- a/services/core/java/com/android/server/job/controllers/AppIdleController.java +++ b/services/core/java/com/android/server/job/controllers/AppIdleController.java @@ -174,7 +174,7 @@ public final class AppIdleController extends StateController { private final class AppIdleStateChangeListener extends UsageStatsManagerInternal.AppIdleStateChangeListener { @Override - public void onAppIdleStateChanged(String packageName, int userId, boolean idle) { + public void onAppIdleStateChanged(String packageName, int userId, boolean idle, int bucket) { boolean changed = false; synchronized (mLock) { if (mAppIdleParoleOn) { diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index 551cb10ffc03..3fa3cd49d393 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -3746,7 +3746,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { extends UsageStatsManagerInternal.AppIdleStateChangeListener { @Override - public void onAppIdleStateChanged(String packageName, int userId, boolean idle) { + public void onAppIdleStateChanged(String packageName, int userId, boolean idle, int bucket) { try { final int uid = mContext.getPackageManager().getPackageUidAsUser(packageName, PackageManager.MATCH_UNINSTALLED_PACKAGES, userId); diff --git a/services/tests/servicestests/src/com/android/server/usage/AppIdleHistoryTests.java b/services/tests/servicestests/src/com/android/server/usage/AppIdleHistoryTests.java index 67ffe5847cbc..39d256a21f16 100644 --- a/services/tests/servicestests/src/com/android/server/usage/AppIdleHistoryTests.java +++ b/services/tests/servicestests/src/com/android/server/usage/AppIdleHistoryTests.java @@ -16,16 +16,14 @@ package com.android.server.usage; -import static android.app.usage.AppStandby.REASON_TIMEOUT; -import static android.app.usage.AppStandby.STANDBY_BUCKET_ACTIVE; -import static android.app.usage.AppStandby.STANDBY_BUCKET_RARE; - import android.app.usage.AppStandby; import android.os.FileUtils; import android.test.AndroidTestCase; import java.io.File; +import static android.app.usage.AppStandby.*; + public class AppIdleHistoryTests extends AndroidTestCase { File mStorageDir; @@ -111,5 +109,9 @@ public class AppIdleHistoryTests extends AndroidTestCase { assertEquals(aih.getAppStandbyBucket(PACKAGE_1, USER_ID, 5000), STANDBY_BUCKET_RARE); assertEquals(aih.getAppStandbyBucket(PACKAGE_2, USER_ID, 5000), STANDBY_BUCKET_ACTIVE); assertEquals(aih.getAppStandbyReason(PACKAGE_1, USER_ID, 5000), REASON_TIMEOUT); + + assertTrue(aih.shouldInformListeners(PACKAGE_1, USER_ID, 5000, STANDBY_BUCKET_RARE)); + assertFalse(aih.shouldInformListeners(PACKAGE_1, USER_ID, 5000, STANDBY_BUCKET_RARE)); + assertTrue(aih.shouldInformListeners(PACKAGE_1, USER_ID, 5000, STANDBY_BUCKET_FREQUENT)); } }
\ No newline at end of file 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 9846d6f6f346..8531baf5f329 100644 --- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java +++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java @@ -16,11 +16,7 @@ package com.android.server.usage; -import static android.app.usage.AppStandby.STANDBY_BUCKET_ACTIVE; -import static android.app.usage.AppStandby.STANDBY_BUCKET_FREQUENT; -import static android.app.usage.AppStandby.STANDBY_BUCKET_RARE; -import static android.app.usage.AppStandby.STANDBY_BUCKET_WORKING_SET; - +import static android.app.usage.AppStandby.*; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; @@ -251,10 +247,22 @@ public class AppStandbyControllerTests { false)); } + private void reportEvent(AppStandbyController controller, long elapsedTime) { + // Back to ACTIVE on event + UsageEvents.Event ev = new UsageEvents.Event(); + ev.mPackage = PACKAGE_1; + ev.mEventType = UsageEvents.Event.USER_INTERACTION; + controller.reportEvent(ev, elapsedTime, USER_ID); + } + @Test public void testBuckets() throws Exception { AppStandbyController controller = setupController(); + assertTimeout(controller, 0, STANDBY_BUCKET_NEVER); + + reportEvent(controller, 0); + // ACTIVE bucket assertTimeout(controller, 11 * HOUR_MS, STANDBY_BUCKET_ACTIVE); @@ -270,11 +278,7 @@ public class AppStandbyControllerTests { // RARE bucket assertTimeout(controller, 9 * DAY_MS, STANDBY_BUCKET_RARE); - // Back to ACTIVE on event - UsageEvents.Event ev = new UsageEvents.Event(); - ev.mPackage = PACKAGE_1; - ev.mEventType = UsageEvents.Event.USER_INTERACTION; - controller.reportEvent(ev, mInjector.mElapsedRealtime, USER_ID); + reportEvent(controller, 9 * DAY_MS); assertTimeout(controller, 9 * DAY_MS, STANDBY_BUCKET_ACTIVE); @@ -287,6 +291,10 @@ public class AppStandbyControllerTests { AppStandbyController controller = setupController(); mInjector.setDisplayOn(false); + assertTimeout(controller, 0, STANDBY_BUCKET_NEVER); + + reportEvent(controller, 0); + // ACTIVE bucket assertTimeout(controller, 11 * HOUR_MS, STANDBY_BUCKET_ACTIVE); diff --git a/services/usage/java/com/android/server/usage/AppIdleHistory.java b/services/usage/java/com/android/server/usage/AppIdleHistory.java index e5d3915dde4c..c5ca33041f41 100644 --- a/services/usage/java/com/android/server/usage/AppIdleHistory.java +++ b/services/usage/java/com/android/server/usage/AppIdleHistory.java @@ -103,7 +103,7 @@ public class AppIdleHistory { long lastUsedScreenTime; @StandbyBuckets int currentBucket; String bucketingReason; - int lastInformedState; + int lastInformedBucket; } AppIdleHistory(File storageDir, long elapsedRealtime) { @@ -333,13 +333,12 @@ public class AppIdleHistory { } boolean shouldInformListeners(String packageName, int userId, - long elapsedRealtime, boolean isIdle) { + long elapsedRealtime, int bucket) { ArrayMap<String, AppUsageHistory> userHistory = getUserHistory(userId); AppUsageHistory appUsageHistory = getPackageHistory(userHistory, packageName, elapsedRealtime, true); - int targetState = isIdle? STATE_IDLE : STATE_ACTIVE; - if (appUsageHistory.lastInformedState != (isIdle ? STATE_IDLE : STATE_ACTIVE)) { - appUsageHistory.lastInformedState = targetState; + if (appUsageHistory.lastInformedBucket != bucket) { + appUsageHistory.lastInformedBucket = bucket; return true; } return false; diff --git a/services/usage/java/com/android/server/usage/AppStandbyController.java b/services/usage/java/com/android/server/usage/AppStandbyController.java index 17fde57907d7..5623a68f158d 100644 --- a/services/usage/java/com/android/server/usage/AppStandbyController.java +++ b/services/usage/java/com/android/server/usage/AppStandbyController.java @@ -160,7 +160,6 @@ public class AppStandbyController { private final Context mContext; // TODO: Provide a mechanism to set an external bucketing service - private boolean mUseInternalBucketingHeuristics = true; private AppWidgetManager mAppWidgetManager; private PowerManager mPowerManager; @@ -367,29 +366,33 @@ public class AppStandbyController { Slog.d(TAG, " Checking idle state for " + packageName); } if (isSpecial) { - maybeInformListeners(packageName, userId, elapsedRealtime, false); - } else if (mUseInternalBucketingHeuristics) { + maybeInformListeners(packageName, userId, elapsedRealtime, + AppStandby.STANDBY_BUCKET_ACTIVE); + } else { synchronized (mAppIdleLock) { - int oldBucket = mAppIdleHistory.getAppStandbyBucket(packageName, userId, - elapsedRealtime); String bucketingReason = mAppIdleHistory.getAppStandbyReason(packageName, userId, elapsedRealtime); - if (bucketingReason != null - && (bucketingReason.equals(AppStandby.REASON_FORCED) - || bucketingReason.startsWith(AppStandby.REASON_PREDICTED))) { + // If the bucket was forced by the developer, leave it alone + if (AppStandby.REASON_FORCED.equals(bucketingReason)) { continue; } - int newBucket = getBucketForLocked(packageName, userId, - elapsedRealtime); - if (DEBUG) { - Slog.d(TAG, " Old bucket=" + oldBucket - + ", newBucket=" + newBucket); - } - if (oldBucket != newBucket) { - mAppIdleHistory.setAppStandbyBucket(packageName, userId, - elapsedRealtime, newBucket, AppStandby.REASON_TIMEOUT); - maybeInformListeners(packageName, userId, elapsedRealtime, - newBucket >= AppStandby.STANDBY_BUCKET_RARE); + // If the bucket was moved up due to usage, let the timeouts apply. + if (AppStandby.REASON_USAGE.equals(bucketingReason) + || AppStandby.REASON_TIMEOUT.equals(bucketingReason)) { + int oldBucket = mAppIdleHistory.getAppStandbyBucket(packageName, userId, + elapsedRealtime); + int newBucket = getBucketForLocked(packageName, userId, + elapsedRealtime); + if (DEBUG) { + Slog.d(TAG, " Old bucket=" + oldBucket + + ", newBucket=" + newBucket); + } + if (oldBucket < newBucket) { + mAppIdleHistory.setAppStandbyBucket(packageName, userId, + elapsedRealtime, newBucket, AppStandby.REASON_TIMEOUT); + maybeInformListeners(packageName, userId, elapsedRealtime, + newBucket); + } } } } @@ -403,12 +406,12 @@ public class AppStandbyController { } private void maybeInformListeners(String packageName, int userId, - long elapsedRealtime, boolean isIdle) { + long elapsedRealtime, int bucket) { synchronized (mAppIdleLock) { if (mAppIdleHistory.shouldInformListeners(packageName, userId, - elapsedRealtime, isIdle)) { + elapsedRealtime, bucket)) { mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS, - userId, isIdle ? 1 : 0, packageName)); + userId, bucket, packageName)); } } } @@ -461,11 +464,13 @@ public class AppStandbyController { if (DEBUG) Slog.i(TAG, "DeviceIdleMode changed to " + deviceIdle); boolean paroled = false; synchronized (mAppIdleLock) { - final long timeSinceLastParole = mInjector.currentTimeMillis() - mLastAppIdleParoledTime; + final long timeSinceLastParole = + mInjector.currentTimeMillis() - mLastAppIdleParoledTime; if (!deviceIdle && timeSinceLastParole >= mAppIdleParoleIntervalMillis) { if (DEBUG) { - Slog.i(TAG, "Bringing idle apps out of inactive state due to deviceIdleMode=false"); + Slog.i(TAG, + "Bringing idle apps out of inactive state due to deviceIdleMode=false"); } paroled = true; } else if (deviceIdle) { @@ -491,7 +496,8 @@ public class AppStandbyController { || event.mEventType == UsageEvents.Event.USER_INTERACTION)) { mAppIdleHistory.reportUsage(event.mPackage, userId, elapsedRealtime); if (previouslyIdle) { - maybeInformListeners(event.mPackage, userId, elapsedRealtime, false); + maybeInformListeners(event.mPackage, userId, elapsedRealtime, + AppStandby.STANDBY_BUCKET_ACTIVE); notifyBatteryStats(event.mPackage, userId, false); } } @@ -729,7 +735,8 @@ public class AppStandbyController { void setAppStandbyBucket(String packageName, int userId, @StandbyBuckets int newBucket, String reason, long elapsedRealtime) { - mAppIdleHistory.setAppStandbyBucket(packageName, userId, elapsedRealtime, newBucket, reason); + mAppIdleHistory.setAppStandbyBucket(packageName, userId, elapsedRealtime, newBucket, + reason); } private boolean isActiveDeviceAdmin(String packageName, int userId) { @@ -786,9 +793,10 @@ public class AppStandbyController { return packageName != null && packageName.equals(activeScorer); } - void informListeners(String packageName, int userId, boolean isIdle) { + void informListeners(String packageName, int userId, int bucket) { + final boolean idle = bucket >= AppStandby.STANDBY_BUCKET_RARE; for (AppIdleStateChangeListener listener : mPackageAccessListeners) { - listener.onAppIdleStateChanged(packageName, userId, isIdle); + listener.onAppIdleStateChanged(packageName, userId, idle, bucket); } } @@ -1037,7 +1045,7 @@ public class AppStandbyController { public void handleMessage(Message msg) { switch (msg.what) { case MSG_INFORM_LISTENERS: - informListeners((String) msg.obj, msg.arg1, msg.arg2 == 1); + informListeners((String) msg.obj, msg.arg1, msg.arg2); break; case MSG_FORCE_IDLE_STATE: @@ -1187,7 +1195,8 @@ public class AppStandbyController { mAppStandbyScreenThresholds = parseLongArray(screenThresholdsValue, SCREEN_TIME_THRESHOLDS); - String elapsedThresholdsValue = mParser.getString(KEY_ELAPSED_TIME_THRESHOLDS, null); + String elapsedThresholdsValue = mParser.getString(KEY_ELAPSED_TIME_THRESHOLDS, + null); mAppStandbyElapsedThresholds = parseLongArray(elapsedThresholdsValue, ELAPSED_TIME_THRESHOLDS); } |