diff options
author | Kweku Adams <kwekua@google.com> | 2020-05-14 14:47:36 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2020-05-14 14:47:36 +0000 |
commit | 84e2f0c5821a6bb6d0b945673323879ec67e9cd2 (patch) | |
tree | c59ff0b58e0b99b0b23f4dcb5929d1a45cc9e13d /apex/jobscheduler | |
parent | fc48f7e52a9e3f0ad0943db383f33d6f9bbb8899 (diff) | |
parent | 95cd952b470e2369749ab9cc98c85714157344cd (diff) |
Merge "Partially exempt headless system apps from app standby." into rvc-dev
Diffstat (limited to 'apex/jobscheduler')
-rw-r--r-- | apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java | 10 | ||||
-rw-r--r-- | apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java | 121 |
2 files changed, 107 insertions, 24 deletions
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java b/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java index 46d449a9257c..372ec981df02 100644 --- a/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java +++ b/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java @@ -79,6 +79,12 @@ public class AppIdleHistory { private static final int STANDBY_BUCKET_UNKNOWN = -1; + /** + * The bucket beyond which apps are considered idle. Any apps in this bucket or lower are + * considered idle while those in higher buckets are not considered idle. + */ + static final int IDLE_BUCKET_CUTOFF = STANDBY_BUCKET_RARE; + @VisibleForTesting static final String APP_IDLE_FILENAME = "app_idle_stats.xml"; private static final String TAG_PACKAGES = "packages"; @@ -350,7 +356,7 @@ public class AppIdleHistory { ArrayMap<String, AppUsageHistory> userHistory = getUserHistory(userId); AppUsageHistory appUsageHistory = getPackageHistory(userHistory, packageName, elapsedRealtime, true); - return appUsageHistory.currentBucket >= STANDBY_BUCKET_RARE; + return appUsageHistory.currentBucket >= IDLE_BUCKET_CUTOFF; } public AppUsageHistory getAppUsageHistory(String packageName, int userId, @@ -487,7 +493,7 @@ public class AppIdleHistory { final int newBucket; final int reason; if (idle) { - newBucket = STANDBY_BUCKET_RARE; + newBucket = IDLE_BUCKET_CUTOFF; reason = REASON_MAIN_FORCED_BY_USER; } else { newBucket = STANDBY_BUCKET_ACTIVE; diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java index 980372d58f33..2834ab14f28d 100644 --- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java +++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java @@ -54,6 +54,7 @@ import static com.android.server.SystemService.PHASE_BOOT_COMPLETED; import static com.android.server.SystemService.PHASE_SYSTEM_SERVICES_READY; import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.UserIdInt; import android.app.ActivityManager; import android.app.AppGlobals; @@ -92,6 +93,7 @@ import android.os.SystemClock; import android.os.UserHandle; import android.provider.Settings.Global; import android.telephony.TelephonyManager; +import android.util.ArrayMap; import android.util.ArraySet; import android.util.KeyValueListParser; import android.util.Slog; @@ -227,6 +229,13 @@ public class AppStandbyController implements AppStandbyInternal { @GuardedBy("mActiveAdminApps") private final SparseArray<Set<String>> mActiveAdminApps = new SparseArray<>(); + /** + * Set of system apps that are headless (don't have any declared activities, enabled or + * disabled). Presence in this map indicates that the app is a headless system app. + */ + @GuardedBy("mAppIdleLock") + private final ArrayMap<String, Boolean> mHeadlessSystemApps = new ArrayMap<>(); + private final CountDownLatch mAdminDataAvailableLatch = new CountDownLatch(1); // Messages for the handler @@ -667,20 +676,22 @@ public class AppStandbyController implements AppStandbyInternal { return; } } - final boolean isSpecial = isAppSpecial(packageName, + final int minBucket = getAppMinBucket(packageName, UserHandle.getAppId(uid), userId); if (DEBUG) { - Slog.d(TAG, " Checking idle state for " + packageName + " special=" + - isSpecial); + Slog.d(TAG, " Checking idle state for " + packageName + + " minBucket=" + minBucket); } - if (isSpecial) { + if (minBucket <= STANDBY_BUCKET_ACTIVE) { + // No extra processing needed for ACTIVE or higher since apps can't drop into lower + // buckets. synchronized (mAppIdleLock) { mAppIdleHistory.setAppStandbyBucket(packageName, userId, elapsedRealtime, - STANDBY_BUCKET_EXEMPTED, REASON_MAIN_DEFAULT); + minBucket, REASON_MAIN_DEFAULT); } maybeInformListeners(packageName, userId, elapsedRealtime, - STANDBY_BUCKET_EXEMPTED, REASON_MAIN_DEFAULT, false); + minBucket, REASON_MAIN_DEFAULT, false); } else { synchronized (mAppIdleLock) { final AppIdleHistory.AppUsageHistory app = @@ -761,6 +772,14 @@ public class AppStandbyController implements AppStandbyInternal { Slog.d(TAG, "Bringing up from RESTRICTED to RARE due to off switch"); } } + if (newBucket > minBucket) { + newBucket = minBucket; + // Leave the reason alone. + if (DEBUG) { + Slog.d(TAG, "Bringing up from " + newBucket + " to " + minBucket + + " due to min bucketing"); + } + } if (DEBUG) { Slog.d(TAG, " Old bucket=" + oldBucket + ", newBucket=" + newBucket); @@ -1027,20 +1046,35 @@ public class AppStandbyController implements AppStandbyInternal { return isAppIdleFiltered(packageName, getAppId(packageName), userId, elapsedRealtime); } - private boolean isAppSpecial(String packageName, int appId, int userId) { - if (packageName == null) return false; + @StandbyBuckets + private int getAppMinBucket(String packageName, int userId) { + try { + final int uid = mPackageManager.getPackageUidAsUser(packageName, userId); + return getAppMinBucket(packageName, UserHandle.getAppId(uid), userId); + } catch (PackageManager.NameNotFoundException e) { + // Not a valid package for this user, nothing to do + return STANDBY_BUCKET_NEVER; + } + } + + /** + * Return the lowest bucket this app should ever enter. + */ + @StandbyBuckets + private int getAppMinBucket(String packageName, int appId, int userId) { + if (packageName == null) return STANDBY_BUCKET_NEVER; // If not enabled at all, of course nobody is ever idle. if (!mAppIdleEnabled) { - return true; + return STANDBY_BUCKET_EXEMPTED; } if (appId < Process.FIRST_APPLICATION_UID) { // System uids never go idle. - return true; + return STANDBY_BUCKET_EXEMPTED; } if (packageName.equals("android")) { // Nor does the framework (which should be redundant with the above, but for MR1 we will // retain this for safety). - return true; + return STANDBY_BUCKET_EXEMPTED; } if (mSystemServicesReady) { try { @@ -1048,42 +1082,51 @@ public class AppStandbyController implements AppStandbyInternal { // for idle mode, because app idle (aka app standby) is really not as big an issue // for controlling who participates vs. doze mode. if (mInjector.isNonIdleWhitelisted(packageName)) { - return true; + return STANDBY_BUCKET_EXEMPTED; } } catch (RemoteException re) { throw re.rethrowFromSystemServer(); } if (isActiveDeviceAdmin(packageName, userId)) { - return true; + return STANDBY_BUCKET_EXEMPTED; } if (isActiveNetworkScorer(packageName)) { - return true; + return STANDBY_BUCKET_EXEMPTED; } if (mAppWidgetManager != null && mInjector.isBoundWidgetPackage(mAppWidgetManager, packageName, userId)) { - return true; + // TODO: consider lowering to ACTIVE + return STANDBY_BUCKET_EXEMPTED; } if (isDeviceProvisioningPackage(packageName)) { - return true; + return STANDBY_BUCKET_EXEMPTED; } } // Check this last, as it can be the most expensive check if (isCarrierApp(packageName)) { - return true; + return STANDBY_BUCKET_EXEMPTED; } - return false; + if (isHeadlessSystemApp(packageName)) { + return STANDBY_BUCKET_ACTIVE; + } + + return STANDBY_BUCKET_NEVER; + } + + private boolean isHeadlessSystemApp(String packageName) { + return mHeadlessSystemApps.containsKey(packageName); } @Override public boolean isAppIdleFiltered(String packageName, int appId, int userId, long elapsedRealtime) { - if (isAppSpecial(packageName, appId, userId)) { + if (getAppMinBucket(packageName, appId, userId) < AppIdleHistory.IDLE_BUCKET_CUTOFF) { return false; } else { synchronized (mAppIdleLock) { @@ -1423,6 +1466,8 @@ public class AppStandbyController implements AppStandbyInternal { } } + // Make sure we don't put the app in a lower bucket than it's supposed to be in. + newBucket = Math.min(newBucket, getAppMinBucket(packageName, userId)); mAppIdleHistory.setAppStandbyBucket(packageName, userId, elapsedRealtime, newBucket, reason, resetTimeout); } @@ -1617,14 +1662,16 @@ public class AppStandbyController implements AppStandbyInternal { @Override public void onReceive(Context context, Intent intent) { final String action = intent.getAction(); + final String pkgName = intent.getData().getSchemeSpecificPart(); + final int userId = getSendingUserId(); if (Intent.ACTION_PACKAGE_ADDED.equals(action) || Intent.ACTION_PACKAGE_CHANGED.equals(action)) { clearCarrierPrivilegedApps(); + // ACTION_PACKAGE_ADDED is called even for system app downgrades. + evaluateSystemAppException(pkgName, userId); } if ((Intent.ACTION_PACKAGE_REMOVED.equals(action) || 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 { @@ -1634,6 +1681,34 @@ public class AppStandbyController implements AppStandbyInternal { } } + private void evaluateSystemAppException(String packageName, int userId) { + if (!mSystemServicesReady) { + // The app will be evaluated in initializeDefaultsForSystemApps() when possible. + return; + } + try { + PackageInfo pi = mPackageManager.getPackageInfoAsUser(packageName, + PackageManager.GET_ACTIVITIES | PackageManager.MATCH_DISABLED_COMPONENTS, + userId); + evaluateSystemAppException(pi); + } catch (PackageManager.NameNotFoundException e) { + mHeadlessSystemApps.remove(packageName); + } + } + + private void evaluateSystemAppException(@Nullable PackageInfo pkgInfo) { + if (pkgInfo.applicationInfo != null && pkgInfo.applicationInfo.isSystemApp()) { + synchronized (mAppIdleLock) { + if (pkgInfo.activities == null || pkgInfo.activities.length == 0) { + // Headless system app. + mHeadlessSystemApps.put(pkgInfo.packageName, true); + } else { + mHeadlessSystemApps.remove(pkgInfo.packageName); + } + } + } + } + @Override public void initializeDefaultsForSystemApps(int userId) { if (!mSystemServicesReady) { @@ -1645,7 +1720,7 @@ public class AppStandbyController implements AppStandbyInternal { + "appIdleEnabled=" + mAppIdleEnabled); final long elapsedRealtime = mInjector.elapsedRealtime(); List<PackageInfo> packages = mPackageManager.getInstalledPackagesAsUser( - PackageManager.MATCH_DISABLED_COMPONENTS, + PackageManager.GET_ACTIVITIES | PackageManager.MATCH_DISABLED_COMPONENTS, userId); final int packageCount = packages.size(); synchronized (mAppIdleLock) { @@ -1658,6 +1733,8 @@ public class AppStandbyController implements AppStandbyInternal { mAppIdleHistory.reportUsage(packageName, userId, STANDBY_BUCKET_ACTIVE, REASON_SUB_USAGE_SYSTEM_UPDATE, 0, elapsedRealtime + mSystemUpdateUsageTimeoutMillis); + + evaluateSystemAppException(pi); } } // Immediately persist defaults to disk |