diff options
author | 2025-02-28 10:01:58 -0800 | |
---|---|---|
committer | 2025-02-28 10:01:58 -0800 | |
commit | d7459438ca3e211dd578dd9d9d9909fa46c3f06c (patch) | |
tree | 439e15b8977f34f2e4cb3aff5a2f735ab0901650 /apex | |
parent | 249b8998c512a2d91d52ef929443b261056989e3 (diff) | |
parent | 7b76c7015d06d334da838ed0cf2c9b36e50c8092 (diff) |
Merge "Persist list of restored apps whose buckets need to be elevated." into main
Diffstat (limited to 'apex')
3 files changed, 102 insertions, 6 deletions
diff --git a/apex/jobscheduler/service/aconfig/app_idle.aconfig b/apex/jobscheduler/service/aconfig/app_idle.aconfig index 74d2a590086f..899341016148 100644 --- a/apex/jobscheduler/service/aconfig/app_idle.aconfig +++ b/apex/jobscheduler/service/aconfig/app_idle.aconfig @@ -28,3 +28,14 @@ flag { description: "Adjust the default bucket evaluation parameters" bug: "379909479" } + +flag { + name: "persist_restore_to_rare_apps_list" + namespace: "backstage_power" + description: "Persist the list of apps which are put in the RARE bucket upon restore." + is_fixed_read_only: true + bug: "383766428" + metadata { + purpose: PURPOSE_BUGFIX + } +} 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 a8641ae43509..4acfebc536eb 100644 --- a/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java +++ b/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java @@ -38,6 +38,7 @@ import android.app.usage.AppStandbyInfo; import android.app.usage.UsageStatsManager; import android.os.SystemClock; import android.util.ArrayMap; +import android.util.ArraySet; import android.util.AtomicFile; import android.util.IndentingPrintWriter; import android.util.Slog; @@ -83,6 +84,9 @@ public class AppIdleHistory { private SparseArray<ArrayMap<String,AppUsageHistory>> mIdleHistory = new SparseArray<>(); private static final long ONE_MINUTE = 60 * 1000; + // Only keep the persisted restore-to-rare apps list for 2 days. + static final long RESTORE_TO_RARE_APPS_LIST_EXPIRY = ONE_MINUTE * 60 * 24 * 2; + static final int STANDBY_BUCKET_UNKNOWN = -1; /** @@ -277,6 +281,58 @@ public class AppIdleHistory { writeScreenOnTime(); } + private File getRestoreToRareAppsListFile(int userId) { + return new File(getUserDirectory(userId), "restore_to_rare_apps_list"); + } + + public ArraySet<String> readRestoreToRareAppsList(int userId) { + File restoreToRareAppsListFile = getRestoreToRareAppsListFile(userId); + if (!restoreToRareAppsListFile.exists()) { + return null; + } + + try (BufferedReader reader = + new BufferedReader(new FileReader(restoreToRareAppsListFile))) { + final ArraySet<String> appsList = new ArraySet<>(); + final long restoreTime = Long.parseLong(reader.readLine()); + if (System.currentTimeMillis() - restoreTime > RESTORE_TO_RARE_APPS_LIST_EXPIRY) { + // the apps list should only be kept around for 2 days + reader.close(); + restoreToRareAppsListFile.delete(); + return null; + } + String pkgName; + while ((pkgName = reader.readLine()) != null) { + appsList.add(pkgName); + } + return appsList; + } catch (IOException | NumberFormatException e) { + return null; + } + } + + public void writeRestoreToRareAppsList(int userId, ArraySet<String> restoreAppsToRare) { + File fileHandle = getRestoreToRareAppsListFile(userId); + if (fileHandle.exists()) { + // don't update the persisted file - it should only be written once. + return; + } + AtomicFile restoreToRareAppsListFile = new AtomicFile(fileHandle); + FileOutputStream fos = null; + try { + fos = restoreToRareAppsListFile.startWrite(); + final StringBuilder sb = new StringBuilder(); + sb.append(System.currentTimeMillis()).append("\n"); + for (String pkgName : restoreAppsToRare) { + sb.append(pkgName).append("\n"); + } + fos.write(sb.toString().getBytes()); + restoreToRareAppsListFile.finishWrite(fos); + } catch (IOException ioe) { + restoreToRareAppsListFile.failWrite(fos); + } + } + /** * Mark the app as used and update the bucket if necessary. If there is a expiry time specified * that's in the future, then the usage event is temporary and keeps the app in the specified @@ -694,10 +750,13 @@ public class AppIdleHistory { return appUsageHistory.bucketExpiryTimesMs.get(bucket, 0); } + private File getUserDirectory(int userId) { + return new File(new File(mStorageDir, "users"), Integer.toString(userId)); + } + @VisibleForTesting File getUserFile(int userId) { - return new File(new File(new File(mStorageDir, "users"), - Integer.toString(userId)), APP_IDLE_FILENAME); + return new File(getUserDirectory(userId), APP_IDLE_FILENAME); } void clearLastUsedTimestamps(String packageName, int userId) { 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 ab8131ba5126..b87b5ceebd98 100644 --- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java +++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java @@ -1706,10 +1706,18 @@ public class AppStandbyController restoreAppToRare(packageName, userId, nowElapsed, reason); } // Clear out the list of restored apps that need to have their standby buckets adjusted - // if they still haven't been installed eight hours after restore. - // Note: if the device reboots within these first 8 hours, this list will be lost since it's - // not persisted - this is the expected behavior for now and may be updated in the future. - mHandler.postDelayed(() -> mAppsToRestoreToRare.remove(userId), 8 * ONE_HOUR); + // if they still haven't been installed two days after initial restore. + final long delayMillis = Flags.persistRestoreToRareAppsList() + ? AppIdleHistory.RESTORE_TO_RARE_APPS_LIST_EXPIRY : 8 * ONE_HOUR; + mHandler.postDelayed(() -> mAppsToRestoreToRare.remove(userId), delayMillis); + + // Persist the file in case the device reboots within 2 days after the initial restore. + if (Flags.persistRestoreToRareAppsList()) { + synchronized (mAppIdleLock) { + mAppIdleHistory.writeRestoreToRareAppsList( + userId, mAppsToRestoreToRare.get(userId)); + } + } } /** Adjust the standby bucket of the given package for the user to RARE. */ @@ -2272,6 +2280,22 @@ public class AppStandbyController } else if (!Intent.ACTION_PACKAGE_ADDED.equals(action)) { clearAppIdleForPackage(pkgName, userId); } else { + // Do a lazy read of the persisted list, if necessary. + if (Flags.persistRestoreToRareAppsList() + && mAppsToRestoreToRare.get(userId) == null) { + synchronized (mAppIdleLock) { + final ArraySet<String> restoredApps = + mAppIdleHistory.readRestoreToRareAppsList(userId); + if (restoredApps != null) { + mAppsToRestoreToRare.addAll(userId, restoredApps); + // Clear out the list of restored apps if they still haven't been + // installed in two days - at worst, we are allowing for up to + // 4 days for reinstallation (device reboots just before 2 days) + mHandler.postDelayed(() -> mAppsToRestoreToRare.remove(userId), + AppIdleHistory.RESTORE_TO_RARE_APPS_LIST_EXPIRY); + } + } + } // Package was just added and it's not being replaced. if (mAppsToRestoreToRare.contains(userId, pkgName)) { restoreAppToRare(pkgName, userId, mInjector.elapsedRealtime(), @@ -2454,6 +2478,8 @@ public class AppStandbyController + ": " + Flags.avoidIdleCheck()); pw.println(" " + Flags.FLAG_ADJUST_DEFAULT_BUCKET_ELEVATION_PARAMS + ": " + Flags.adjustDefaultBucketElevationParams()); + pw.println(" " + Flags.FLAG_PERSIST_RESTORE_TO_RARE_APPS_LIST + + ": " + Flags.persistRestoreToRareAppsList()); pw.println(); synchronized (mCarrierPrivilegedLock) { |