summaryrefslogtreecommitdiff
path: root/apex
diff options
context:
space:
mode:
author Treehugger Robot <android-test-infra-autosubmit@system.gserviceaccount.com> 2025-02-28 10:01:58 -0800
committer Android (Google) Code Review <android-gerrit@google.com> 2025-02-28 10:01:58 -0800
commitd7459438ca3e211dd578dd9d9d9909fa46c3f06c (patch)
tree439e15b8977f34f2e4cb3aff5a2f735ab0901650 /apex
parent249b8998c512a2d91d52ef929443b261056989e3 (diff)
parent7b76c7015d06d334da838ed0cf2c9b36e50c8092 (diff)
Merge "Persist list of restored apps whose buckets need to be elevated." into main
Diffstat (limited to 'apex')
-rw-r--r--apex/jobscheduler/service/aconfig/app_idle.aconfig11
-rw-r--r--apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java63
-rw-r--r--apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java34
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) {