Unrestrict updated buggy apps.
If an app is put into the RESTRICTED bucket because the system thinks it's buggy, we can bring it out of the bucket when the app is updated, assuming that the bug is fixed in the new version. If there are other reasons that the app is restricted, then we don't bring it out. Bug: 149507105 Test: atest FrameworksServicesTests:AppIdleHistoryTests Test: atest FrameworksServicesTests:AppStandbyControllerTests Change-Id: Ie4538dde3b367d32f4260e8301afa0556b845b2a
This commit is contained in:
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
@@ -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) {
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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");
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user