Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d7459438 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Persist list of restored apps whose buckets need to be elevated." into main

parents 249b8998 7b76c701
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -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
    }
}
+61 −2
Original line number Diff line number Diff line
@@ -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) {
+30 −4
Original line number Diff line number Diff line
@@ -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) {