Loading apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java +42 −9 Original line number Diff line number Diff line Loading @@ -23,6 +23,8 @@ import static android.app.usage.UsageStatsManager.REASON_MAIN_MASK; import static android.app.usage.UsageStatsManager.REASON_MAIN_PREDICTED; import static android.app.usage.UsageStatsManager.REASON_MAIN_TIMEOUT; import static android.app.usage.UsageStatsManager.REASON_MAIN_USAGE; import static android.app.usage.UsageStatsManager.REASON_SUB_DEFAULT_APP_UPDATE; import static android.app.usage.UsageStatsManager.REASON_SUB_FORCED_SYSTEM_FLAG_BUGGY; import static android.app.usage.UsageStatsManager.REASON_SUB_MASK; import static android.app.usage.UsageStatsManager.REASON_SUB_PREDICTED_RESTORED; import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_ACTIVE_TIMEOUT; Loading Loading @@ -73,7 +75,6 @@ import android.content.pm.PackageManagerInternal; import android.content.pm.ParceledListSlice; import android.database.ContentObserver; import android.hardware.display.DisplayManager; import android.net.ConnectivityManager; import android.net.NetworkScoreManager; import android.os.BatteryManager; import android.os.BatteryStats; Loading Loading @@ -304,10 +305,7 @@ public class AppStandbyController implements AppStandbyInternal { private final AppStandbyHandler mHandler; private final Context mContext; // TODO: Provide a mechanism to set an external bucketing service private AppWidgetManager mAppWidgetManager; private ConnectivityManager mConnectivityManager; private PackageManager mPackageManager; Injector mInjector; Loading Loading @@ -411,7 +409,6 @@ public class AppStandbyController implements AppStandbyInternal { settingsObserver.updateSettings(); mAppWidgetManager = mContext.getSystemService(AppWidgetManager.class); mConnectivityManager = mContext.getSystemService(ConnectivityManager.class); mInjector.registerDisplayListener(mDisplayListener, mHandler); synchronized (mAppIdleLock) { Loading Loading @@ -1519,6 +1516,38 @@ public class AppStandbyController implements AppStandbyInternal { } } /** * Remove an app from the {@link android.app.usage.UsageStatsManager#STANDBY_BUCKET_RESTRICTED} * bucket if it was forced into the bucket by the system because it was buggy. */ @VisibleForTesting void maybeUnrestrictBuggyApp(String packageName, int userId) { synchronized (mAppIdleLock) { final long elapsedRealtime = mInjector.elapsedRealtime(); final AppIdleHistory.AppUsageHistory app = mAppIdleHistory.getAppUsageHistory(packageName, userId, elapsedRealtime); if (app.currentBucket != STANDBY_BUCKET_RESTRICTED || (app.bucketingReason & REASON_MAIN_MASK) != REASON_MAIN_FORCED_BY_SYSTEM) { return; } final int newBucket; final int newReason; if ((app.bucketingReason & REASON_SUB_MASK) == REASON_SUB_FORCED_SYSTEM_FLAG_BUGGY) { // If bugginess was the only reason the app should be restricted, then lift it out. newBucket = STANDBY_BUCKET_RARE; newReason = REASON_MAIN_DEFAULT | REASON_SUB_DEFAULT_APP_UPDATE; } else { // There's another reason the app was restricted. Remove the buggy bit and call // it a day. newBucket = STANDBY_BUCKET_RESTRICTED; newReason = app.bucketingReason & ~REASON_SUB_FORCED_SYSTEM_FLAG_BUGGY; } mAppIdleHistory.setAppStandbyBucket( packageName, userId, elapsedRealtime, newBucket, newReason); } } private class PackageReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Loading @@ -1528,10 +1557,14 @@ public class AppStandbyController implements AppStandbyInternal { clearCarrierPrivilegedApps(); } if ((Intent.ACTION_PACKAGE_REMOVED.equals(action) || Intent.ACTION_PACKAGE_ADDED.equals(action)) && !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) { clearAppIdleForPackage(intent.getData().getSchemeSpecificPart(), getSendingUserId()); Intent.ACTION_PACKAGE_ADDED.equals(action))) { final String pkgName = intent.getData().getSchemeSpecificPart(); final int userId = getSendingUserId(); if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) { maybeUnrestrictBuggyApp(pkgName, userId); } else { clearAppIdleForPackage(pkgName, userId); } } } } Loading core/java/android/app/usage/UsageStatsManager.java +18 −0 Original line number Diff line number Diff line Loading @@ -203,6 +203,16 @@ public final class UsageStatsManager { /** @hide */ public static final int REASON_SUB_MASK = 0x00FF; /** * The reason for using the default main reason is unknown or undefined. * @hide */ public static final int REASON_SUB_DEFAULT_UNDEFINED = 0x0000; /** * The app was updated. * @hide */ public static final int REASON_SUB_DEFAULT_APP_UPDATE = 0x0001; /** * The app was interacted with in some way by the system. * @hide Loading Loading @@ -1069,6 +1079,14 @@ public final class UsageStatsManager { switch (standbyReason & REASON_MAIN_MASK) { case REASON_MAIN_DEFAULT: sb.append("d"); switch (subReason) { case REASON_SUB_DEFAULT_UNDEFINED: // Historically, undefined didn't have a string, so don't add anything here. break; case REASON_SUB_DEFAULT_APP_UPDATE: sb.append("-au"); break; } break; case REASON_MAIN_FORCED_BY_SYSTEM: sb.append("s"); Loading services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java +74 −0 Original line number Diff line number Diff line Loading @@ -1208,6 +1208,80 @@ public class AppStandbyControllerTests { STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1)); } public void testAppUpdateOnRestrictedBucketStatus() { // Updates shouldn't change bucket if the app timed out. // Way past all timeouts. App times out into RESTRICTED bucket. reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1); mInjector.mElapsedRealtime += RESTRICTED_THRESHOLD * 4; mController.checkIdleStates(USER_ID); assertBucket(STANDBY_BUCKET_RESTRICTED); mController.maybeUnrestrictBuggyApp(PACKAGE_1, USER_ID); assertBucket(STANDBY_BUCKET_RESTRICTED); mController.maybeUnrestrictBuggyApp(PACKAGE_1, USER_ID2); assertBucket(STANDBY_BUCKET_RESTRICTED); mController.maybeUnrestrictBuggyApp("com.random.package", USER_ID); assertBucket(STANDBY_BUCKET_RESTRICTED); // Updates shouldn't change bucket if the app was forced by the system for a non-buggy // reason. reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1); mInjector.mElapsedRealtime += RESTRICTED_THRESHOLD * 4; mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RESTRICTED, REASON_MAIN_FORCED_BY_SYSTEM | REASON_SUB_FORCED_SYSTEM_FLAG_BACKGROUND_RESOURCE_USAGE); mController.maybeUnrestrictBuggyApp(PACKAGE_1, USER_ID); assertBucket(STANDBY_BUCKET_RESTRICTED); mController.maybeUnrestrictBuggyApp(PACKAGE_1, USER_ID2); assertBucket(STANDBY_BUCKET_RESTRICTED); mController.maybeUnrestrictBuggyApp("com.random.package", USER_ID); assertBucket(STANDBY_BUCKET_RESTRICTED); // Updates should change bucket if the app was forced by the system for a buggy reason. reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1); mInjector.mElapsedRealtime += RESTRICTED_THRESHOLD * 4; mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RESTRICTED, REASON_MAIN_FORCED_BY_SYSTEM | REASON_SUB_FORCED_SYSTEM_FLAG_BUGGY); mController.maybeUnrestrictBuggyApp(PACKAGE_1, USER_ID2); assertBucket(STANDBY_BUCKET_RESTRICTED); mController.maybeUnrestrictBuggyApp("com.random.package", USER_ID); assertBucket(STANDBY_BUCKET_RESTRICTED); mController.maybeUnrestrictBuggyApp(PACKAGE_1, USER_ID); assertNotEquals(STANDBY_BUCKET_RESTRICTED, getStandbyBucket(mController, PACKAGE_1)); // Updates shouldn't change bucket if the app was forced by the system for more than just // a buggy reason. reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1); mInjector.mElapsedRealtime += RESTRICTED_THRESHOLD * 4; mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RESTRICTED, REASON_MAIN_FORCED_BY_SYSTEM | REASON_SUB_FORCED_SYSTEM_FLAG_ABUSE | REASON_SUB_FORCED_SYSTEM_FLAG_BUGGY); mController.maybeUnrestrictBuggyApp(PACKAGE_1, USER_ID); assertBucket(STANDBY_BUCKET_RESTRICTED); assertEquals(REASON_MAIN_FORCED_BY_SYSTEM | REASON_SUB_FORCED_SYSTEM_FLAG_ABUSE, getStandbyBucketReason(PACKAGE_1)); mController.maybeUnrestrictBuggyApp(PACKAGE_1, USER_ID2); assertBucket(STANDBY_BUCKET_RESTRICTED); mController.maybeUnrestrictBuggyApp("com.random.package", USER_ID); assertBucket(STANDBY_BUCKET_RESTRICTED); // Updates shouldn't change bucket if the app was forced by the user. reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1); mInjector.mElapsedRealtime += RESTRICTED_THRESHOLD * 4; mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RESTRICTED, REASON_MAIN_FORCED_BY_USER); mController.maybeUnrestrictBuggyApp(PACKAGE_1, USER_ID); assertBucket(STANDBY_BUCKET_RESTRICTED); mController.maybeUnrestrictBuggyApp(PACKAGE_1, USER_ID2); assertBucket(STANDBY_BUCKET_RESTRICTED); mController.maybeUnrestrictBuggyApp("com.random.package", USER_ID); assertBucket(STANDBY_BUCKET_RESTRICTED); } private String getAdminAppsStr(int userId) { return getAdminAppsStr(userId, mController.getActiveAdminAppsForTest(userId)); } Loading Loading
apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java +42 −9 Original line number Diff line number Diff line Loading @@ -23,6 +23,8 @@ import static android.app.usage.UsageStatsManager.REASON_MAIN_MASK; import static android.app.usage.UsageStatsManager.REASON_MAIN_PREDICTED; import static android.app.usage.UsageStatsManager.REASON_MAIN_TIMEOUT; import static android.app.usage.UsageStatsManager.REASON_MAIN_USAGE; import static android.app.usage.UsageStatsManager.REASON_SUB_DEFAULT_APP_UPDATE; import static android.app.usage.UsageStatsManager.REASON_SUB_FORCED_SYSTEM_FLAG_BUGGY; import static android.app.usage.UsageStatsManager.REASON_SUB_MASK; import static android.app.usage.UsageStatsManager.REASON_SUB_PREDICTED_RESTORED; import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_ACTIVE_TIMEOUT; Loading Loading @@ -73,7 +75,6 @@ import android.content.pm.PackageManagerInternal; import android.content.pm.ParceledListSlice; import android.database.ContentObserver; import android.hardware.display.DisplayManager; import android.net.ConnectivityManager; import android.net.NetworkScoreManager; import android.os.BatteryManager; import android.os.BatteryStats; Loading Loading @@ -304,10 +305,7 @@ public class AppStandbyController implements AppStandbyInternal { private final AppStandbyHandler mHandler; private final Context mContext; // TODO: Provide a mechanism to set an external bucketing service private AppWidgetManager mAppWidgetManager; private ConnectivityManager mConnectivityManager; private PackageManager mPackageManager; Injector mInjector; Loading Loading @@ -411,7 +409,6 @@ public class AppStandbyController implements AppStandbyInternal { settingsObserver.updateSettings(); mAppWidgetManager = mContext.getSystemService(AppWidgetManager.class); mConnectivityManager = mContext.getSystemService(ConnectivityManager.class); mInjector.registerDisplayListener(mDisplayListener, mHandler); synchronized (mAppIdleLock) { Loading Loading @@ -1519,6 +1516,38 @@ public class AppStandbyController implements AppStandbyInternal { } } /** * Remove an app from the {@link android.app.usage.UsageStatsManager#STANDBY_BUCKET_RESTRICTED} * bucket if it was forced into the bucket by the system because it was buggy. */ @VisibleForTesting void maybeUnrestrictBuggyApp(String packageName, int userId) { synchronized (mAppIdleLock) { final long elapsedRealtime = mInjector.elapsedRealtime(); final AppIdleHistory.AppUsageHistory app = mAppIdleHistory.getAppUsageHistory(packageName, userId, elapsedRealtime); if (app.currentBucket != STANDBY_BUCKET_RESTRICTED || (app.bucketingReason & REASON_MAIN_MASK) != REASON_MAIN_FORCED_BY_SYSTEM) { return; } final int newBucket; final int newReason; if ((app.bucketingReason & REASON_SUB_MASK) == REASON_SUB_FORCED_SYSTEM_FLAG_BUGGY) { // If bugginess was the only reason the app should be restricted, then lift it out. newBucket = STANDBY_BUCKET_RARE; newReason = REASON_MAIN_DEFAULT | REASON_SUB_DEFAULT_APP_UPDATE; } else { // There's another reason the app was restricted. Remove the buggy bit and call // it a day. newBucket = STANDBY_BUCKET_RESTRICTED; newReason = app.bucketingReason & ~REASON_SUB_FORCED_SYSTEM_FLAG_BUGGY; } mAppIdleHistory.setAppStandbyBucket( packageName, userId, elapsedRealtime, newBucket, newReason); } } private class PackageReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Loading @@ -1528,10 +1557,14 @@ public class AppStandbyController implements AppStandbyInternal { clearCarrierPrivilegedApps(); } if ((Intent.ACTION_PACKAGE_REMOVED.equals(action) || Intent.ACTION_PACKAGE_ADDED.equals(action)) && !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) { clearAppIdleForPackage(intent.getData().getSchemeSpecificPart(), getSendingUserId()); Intent.ACTION_PACKAGE_ADDED.equals(action))) { final String pkgName = intent.getData().getSchemeSpecificPart(); final int userId = getSendingUserId(); if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) { maybeUnrestrictBuggyApp(pkgName, userId); } else { clearAppIdleForPackage(pkgName, userId); } } } } Loading
core/java/android/app/usage/UsageStatsManager.java +18 −0 Original line number Diff line number Diff line Loading @@ -203,6 +203,16 @@ public final class UsageStatsManager { /** @hide */ public static final int REASON_SUB_MASK = 0x00FF; /** * The reason for using the default main reason is unknown or undefined. * @hide */ public static final int REASON_SUB_DEFAULT_UNDEFINED = 0x0000; /** * The app was updated. * @hide */ public static final int REASON_SUB_DEFAULT_APP_UPDATE = 0x0001; /** * The app was interacted with in some way by the system. * @hide Loading Loading @@ -1069,6 +1079,14 @@ public final class UsageStatsManager { switch (standbyReason & REASON_MAIN_MASK) { case REASON_MAIN_DEFAULT: sb.append("d"); switch (subReason) { case REASON_SUB_DEFAULT_UNDEFINED: // Historically, undefined didn't have a string, so don't add anything here. break; case REASON_SUB_DEFAULT_APP_UPDATE: sb.append("-au"); break; } break; case REASON_MAIN_FORCED_BY_SYSTEM: sb.append("s"); Loading
services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java +74 −0 Original line number Diff line number Diff line Loading @@ -1208,6 +1208,80 @@ public class AppStandbyControllerTests { STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1)); } public void testAppUpdateOnRestrictedBucketStatus() { // Updates shouldn't change bucket if the app timed out. // Way past all timeouts. App times out into RESTRICTED bucket. reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1); mInjector.mElapsedRealtime += RESTRICTED_THRESHOLD * 4; mController.checkIdleStates(USER_ID); assertBucket(STANDBY_BUCKET_RESTRICTED); mController.maybeUnrestrictBuggyApp(PACKAGE_1, USER_ID); assertBucket(STANDBY_BUCKET_RESTRICTED); mController.maybeUnrestrictBuggyApp(PACKAGE_1, USER_ID2); assertBucket(STANDBY_BUCKET_RESTRICTED); mController.maybeUnrestrictBuggyApp("com.random.package", USER_ID); assertBucket(STANDBY_BUCKET_RESTRICTED); // Updates shouldn't change bucket if the app was forced by the system for a non-buggy // reason. reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1); mInjector.mElapsedRealtime += RESTRICTED_THRESHOLD * 4; mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RESTRICTED, REASON_MAIN_FORCED_BY_SYSTEM | REASON_SUB_FORCED_SYSTEM_FLAG_BACKGROUND_RESOURCE_USAGE); mController.maybeUnrestrictBuggyApp(PACKAGE_1, USER_ID); assertBucket(STANDBY_BUCKET_RESTRICTED); mController.maybeUnrestrictBuggyApp(PACKAGE_1, USER_ID2); assertBucket(STANDBY_BUCKET_RESTRICTED); mController.maybeUnrestrictBuggyApp("com.random.package", USER_ID); assertBucket(STANDBY_BUCKET_RESTRICTED); // Updates should change bucket if the app was forced by the system for a buggy reason. reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1); mInjector.mElapsedRealtime += RESTRICTED_THRESHOLD * 4; mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RESTRICTED, REASON_MAIN_FORCED_BY_SYSTEM | REASON_SUB_FORCED_SYSTEM_FLAG_BUGGY); mController.maybeUnrestrictBuggyApp(PACKAGE_1, USER_ID2); assertBucket(STANDBY_BUCKET_RESTRICTED); mController.maybeUnrestrictBuggyApp("com.random.package", USER_ID); assertBucket(STANDBY_BUCKET_RESTRICTED); mController.maybeUnrestrictBuggyApp(PACKAGE_1, USER_ID); assertNotEquals(STANDBY_BUCKET_RESTRICTED, getStandbyBucket(mController, PACKAGE_1)); // Updates shouldn't change bucket if the app was forced by the system for more than just // a buggy reason. reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1); mInjector.mElapsedRealtime += RESTRICTED_THRESHOLD * 4; mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RESTRICTED, REASON_MAIN_FORCED_BY_SYSTEM | REASON_SUB_FORCED_SYSTEM_FLAG_ABUSE | REASON_SUB_FORCED_SYSTEM_FLAG_BUGGY); mController.maybeUnrestrictBuggyApp(PACKAGE_1, USER_ID); assertBucket(STANDBY_BUCKET_RESTRICTED); assertEquals(REASON_MAIN_FORCED_BY_SYSTEM | REASON_SUB_FORCED_SYSTEM_FLAG_ABUSE, getStandbyBucketReason(PACKAGE_1)); mController.maybeUnrestrictBuggyApp(PACKAGE_1, USER_ID2); assertBucket(STANDBY_BUCKET_RESTRICTED); mController.maybeUnrestrictBuggyApp("com.random.package", USER_ID); assertBucket(STANDBY_BUCKET_RESTRICTED); // Updates shouldn't change bucket if the app was forced by the user. reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1); mInjector.mElapsedRealtime += RESTRICTED_THRESHOLD * 4; mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RESTRICTED, REASON_MAIN_FORCED_BY_USER); mController.maybeUnrestrictBuggyApp(PACKAGE_1, USER_ID); assertBucket(STANDBY_BUCKET_RESTRICTED); mController.maybeUnrestrictBuggyApp(PACKAGE_1, USER_ID2); assertBucket(STANDBY_BUCKET_RESTRICTED); mController.maybeUnrestrictBuggyApp("com.random.package", USER_ID); assertBucket(STANDBY_BUCKET_RESTRICTED); } private String getAdminAppsStr(int userId) { return getAdminAppsStr(userId, mController.getActiveAdminAppsForTest(userId)); } Loading