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

Commit a8505b54 authored by Svet Ganov's avatar Svet Ganov Committed by android-build-merger
Browse files

Prune unused static libs and instant apps if space needed

am: f36d53cb

Change-Id: I0fdca2a5069b6f3572a9cb5fe0d3ead0442b7b46
parents 41134f38 f36d53cb
Loading
Loading
Loading
Loading
+39 −3
Original line number Diff line number Diff line
@@ -9817,13 +9817,49 @@ public final class Settings {
        public static final String ENABLE_EPHEMERAL_FEATURE = "enable_ephemeral_feature";

        /**
         * The duration for caching uninstalled instant apps.
         * The min period for caching installed instant apps in milliseconds.
         * <p>
         * Type: long
         * @hide
         */
        public static final String UNINSTALLED_INSTANT_APP_CACHE_DURATION_MILLIS =
                "uninstalled_instant_app_cache_duration_millis";
        public static final String INSTALLED_INSTANT_APP_MIN_CACHE_PERIOD =
                "installed_instant_app_min_cache_period";

        /**
         * The max period for caching installed instant apps in milliseconds.
         * <p>
         * Type: long
         * @hide
         */
        public static final String INSTALLED_INSTANT_APP_MAX_CACHE_PERIOD =
                "installed_instant_app_max_cache_period";

        /**
         * The min period for caching uninstalled instant apps in milliseconds.
         * <p>
         * Type: long
         * @hide
         */
        public static final String UNINSTALLED_INSTANT_APP_MIN_CACHE_PERIOD =
                "uninstalled_instant_app_min_cache_period";

        /**
         * The max period for caching uninstalled instant apps in milliseconds.
         * <p>
         * Type: long
         * @hide
         */
        public static final String UNINSTALLED_INSTANT_APP_MAX_CACHE_PERIOD =
                "uninstalled_instant_app_max_cache_period";

        /**
         * The min period for caching unused static shared libs in milliseconds.
         * <p>
         * Type: long
         * @hide
         */
        public static final String UNUSED_STATIC_SHARED_LIB_MIN_CACHE_PERIOD =
                "unused_static_shared_lib_min_cache_period";

        /**
         * Allows switching users when system user is locked.
+5 −1
Original line number Diff line number Diff line
@@ -310,7 +310,7 @@ message GlobalSettingsProto {
    SettingProto lte_service_forced = 265;
    SettingProto ephemeral_cookie_max_size_bytes = 266;
    SettingProto enable_ephemeral_feature = 267;
    SettingProto uninstalled_ephemeral_app_cache_duration_millis = 268;
    SettingProto installed_instant_app_min_cache_period = 268;
    SettingProto allow_user_switching_when_system_user_locked = 269;
    SettingProto boot_count = 270;
    SettingProto safe_boot_disallowed = 271;
@@ -331,6 +331,10 @@ message GlobalSettingsProto {
    SettingProto network_recommendations_package = 286;
    SettingProto bluetooth_a2dp_supports_optional_codecs_prefix = 287;
    SettingProto bluetooth_a2dp_optional_codecs_enabled_prefix = 288;
    SettingProto installed_instant_app_max_cache_period = 289;
    SettingProto uninstalled_instant_app_min_cache_period = 290;
    SettingProto uninstalled_instant_app_max_cache_period = 291;
    SettingProto unused_static_shared_lib_min_cache_period = 292;
}

message SecureSettingsProto {
+5 −1
Original line number Diff line number Diff line
@@ -334,7 +334,11 @@ public class SettingsBackupTest {
                    Settings.Global.TRUSTED_SOUND,
                    Settings.Global.TZINFO_UPDATE_CONTENT_URL,
                    Settings.Global.TZINFO_UPDATE_METADATA_URL,
                    Settings.Global.UNINSTALLED_INSTANT_APP_CACHE_DURATION_MILLIS,
                    Settings.Global.INSTALLED_INSTANT_APP_MIN_CACHE_PERIOD,
                    Settings.Global.INSTALLED_INSTANT_APP_MAX_CACHE_PERIOD,
                    Settings.Global.UNINSTALLED_INSTANT_APP_MIN_CACHE_PERIOD,
                    Settings.Global.UNINSTALLED_INSTANT_APP_MAX_CACHE_PERIOD,
                    Settings.Global.UNUSED_STATIC_SHARED_LIB_MIN_CACHE_PERIOD,
                    Settings.Global.UNLOCK_SOUND,
                    Settings.Global.USE_GOOGLE_MAIL,
                    Settings.Global.VT_IMS_ENABLED,
+14 −2
Original line number Diff line number Diff line
@@ -888,8 +888,20 @@ class SettingsProtoDumpUtil {
                Settings.Global.ENABLE_EPHEMERAL_FEATURE,
                GlobalSettingsProto.ENABLE_EPHEMERAL_FEATURE);
        dumpSetting(s, p,
                Settings.Global.UNINSTALLED_INSTANT_APP_CACHE_DURATION_MILLIS,
                GlobalSettingsProto.UNINSTALLED_EPHEMERAL_APP_CACHE_DURATION_MILLIS);
                Settings.Global.UNINSTALLED_INSTANT_APP_MIN_CACHE_PERIOD,
                GlobalSettingsProto.UNINSTALLED_INSTANT_APP_MIN_CACHE_PERIOD);
        dumpSetting(s, p,
                Settings.Global.UNINSTALLED_INSTANT_APP_MAX_CACHE_PERIOD,
                GlobalSettingsProto.UNINSTALLED_INSTANT_APP_MAX_CACHE_PERIOD);
        dumpSetting(s, p,
                Settings.Global.INSTALLED_INSTANT_APP_MIN_CACHE_PERIOD,
                GlobalSettingsProto.INSTALLED_INSTANT_APP_MIN_CACHE_PERIOD);
        dumpSetting(s, p,
                Settings.Global.INSTALLED_INSTANT_APP_MAX_CACHE_PERIOD,
                GlobalSettingsProto.INSTALLED_INSTANT_APP_MAX_CACHE_PERIOD);
        dumpSetting(s, p,
                Settings.Global.UNUSED_STATIC_SHARED_LIB_MIN_CACHE_PERIOD,
                GlobalSettingsProto.UNUSED_STATIC_SHARED_LIB_MIN_CACHE_PERIOD);
        dumpSetting(s, p,
                Settings.Global.ALLOW_USER_SWITCHING_WHEN_SYSTEM_USER_LOCKED,
                GlobalSettingsProto.ALLOW_USER_SWITCHING_WHEN_SYSTEM_USER_LOCKED);
+191 −30
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.content.Intent;
import android.content.pm.InstantAppInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageParser;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
@@ -32,6 +33,8 @@ import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.UserHandle;
import android.os.storage.StorageManager;
import android.provider.Settings;
import android.util.ArrayMap;
import android.util.AtomicFile;
@@ -76,7 +79,16 @@ class InstantAppRegistry {

    private static final String LOG_TAG = "InstantAppRegistry";

    private static final long DEFAULT_UNINSTALLED_INSTANT_APP_CACHE_DURATION_MILLIS =
    static final long DEFAULT_INSTALLED_INSTANT_APP_MIN_CACHE_PERIOD =
            DEBUG ? 30 * 1000L /* thirty seconds */ : 7 * 24 * 60 * 60 * 1000L; /* one week */

    private static final long DEFAULT_INSTALLED_INSTANT_APP_MAX_CACHE_PERIOD =
            DEBUG ? 60 * 1000L /* one min */ : 6 * 30 * 24 * 60 * 60 * 1000L; /* six months */

    static final long DEFAULT_UNINSTALLED_INSTANT_APP_MIN_CACHE_PERIOD =
            DEBUG ? 30 * 1000L /* thirty seconds */ : 7 * 24 * 60 * 60 * 1000L; /* one week */

    private static final long DEFAULT_UNINSTALLED_INSTANT_APP_MAX_CACHE_PERIOD =
            DEBUG ? 60 * 1000L /* one min */ : 6 * 30 * 24 * 60 * 60 * 1000L; /* six months */

    private static final String INSTANT_APPS_FOLDER = "instant";
@@ -535,18 +547,161 @@ class InstantAppRegistry {
        }
    }

    public void pruneInstantAppsLPw() {
        // For now we prune only state for uninstalled instant apps
        final long maxCacheDurationMillis = Settings.Global.getLong(
    void pruneInstantApps() {
        final long maxInstalledCacheDuration = Settings.Global.getLong(
                mService.mContext.getContentResolver(),
                Settings.Global.INSTALLED_INSTANT_APP_MAX_CACHE_PERIOD,
                DEFAULT_INSTALLED_INSTANT_APP_MAX_CACHE_PERIOD);

        final long maxUninstalledCacheDuration = Settings.Global.getLong(
                mService.mContext.getContentResolver(),
                Settings.Global.UNINSTALLED_INSTANT_APP_CACHE_DURATION_MILLIS,
                DEFAULT_UNINSTALLED_INSTANT_APP_CACHE_DURATION_MILLIS);
                Settings.Global.UNINSTALLED_INSTANT_APP_MAX_CACHE_PERIOD,
                DEFAULT_UNINSTALLED_INSTANT_APP_MAX_CACHE_PERIOD);

        try {
            pruneInstantApps(Long.MAX_VALUE,
                    maxInstalledCacheDuration, maxUninstalledCacheDuration);
        } catch (IOException e) {
            Slog.e(LOG_TAG, "Error pruning installed and uninstalled instant apps", e);
        }
    }

    boolean pruneInstalledInstantApps(long neededSpace, long maxInstalledCacheDuration) {
        try {
            return pruneInstantApps(neededSpace, maxInstalledCacheDuration, Long.MAX_VALUE);
        } catch (IOException e) {
            Slog.e(LOG_TAG, "Error pruning installed instant apps", e);
            return false;
        }
    }

    boolean pruneUninstalledInstantApps(long neededSpace, long maxUninstalledCacheDuration) {
        try {
            return pruneInstantApps(neededSpace, Long.MAX_VALUE, maxUninstalledCacheDuration);
        } catch (IOException e) {
            Slog.e(LOG_TAG, "Error pruning uninstalled instant apps", e);
            return false;
        }
    }

    /**
     * Prunes instant apps until there is enough <code>neededSpace</code>. Both
     * installed and uninstalled instant apps are pruned that are older than
     * <code>maxInstalledCacheDuration</code> and <code>maxUninstalledCacheDuration</code>
     * respectively. All times are in milliseconds.
     *
     * @param neededSpace The space to ensure is free.
     * @param maxInstalledCacheDuration The max duration for caching installed apps in millis.
     * @param maxUninstalledCacheDuration The max duration for caching uninstalled apps in millis.
     * @return Whether enough space was freed.
     *
     * @throws IOException
     */
    private boolean pruneInstantApps(long neededSpace, long maxInstalledCacheDuration,
            long maxUninstalledCacheDuration) throws IOException {
        final StorageManager storage = mService.mContext.getSystemService(StorageManager.class);
        final File file = storage.findPathForUuid(StorageManager.UUID_PRIVATE_INTERNAL);

        if (file.getUsableSpace() >= neededSpace) {
            return true;
        }

        List<String> packagesToDelete = null;

        final int[] allUsers;
        final long now = System.currentTimeMillis();

        // Prune first installed instant apps
        synchronized (mService.mPackages) {
            allUsers = PackageManagerService.sUserManager.getUserIds();

            final int packageCount = mService.mPackages.size();
            for (int i = 0; i < packageCount; i++) {
                final PackageParser.Package pkg = mService.mPackages.valueAt(i);
                if (now - pkg.getLatestPackageUseTimeInMills() < maxInstalledCacheDuration) {
                    continue;
                }
                if (!(pkg.mExtras instanceof PackageSetting)) {
                    continue;
                }
                final PackageSetting  ps = (PackageSetting) pkg.mExtras;
                boolean installedOnlyAsInstantApp = false;
                for (int userId : allUsers) {
                    if (ps.getInstalled(userId)) {
                        if (ps.getInstantApp(userId)) {
                            installedOnlyAsInstantApp = true;
                        } else {
                            installedOnlyAsInstantApp = false;
                            break;
                        }
                    }
                }
                if (installedOnlyAsInstantApp) {
                    if (packagesToDelete == null) {
                        packagesToDelete = new ArrayList<>();
                    }
                    packagesToDelete.add(pkg.packageName);
                }
            }

            if (packagesToDelete != null) {
                packagesToDelete.sort((String lhs, String rhs) -> {
                    final PackageParser.Package lhsPkg = mService.mPackages.get(lhs);
                    final PackageParser.Package rhsPkg = mService.mPackages.get(rhs);
                    if (lhsPkg == null && rhsPkg == null) {
                        return 0;
                    } else if (lhsPkg == null) {
                        return -1;
                    } else if (rhsPkg == null) {
                        return 1;
                    } else {
                        if (lhsPkg.getLatestPackageUseTimeInMills() >
                                rhsPkg.getLatestPackageUseTimeInMills()) {
                            return 1;
                        } else if (lhsPkg.getLatestPackageUseTimeInMills() <
                                rhsPkg.getLatestPackageUseTimeInMills()) {
                            return -1;
                        } else {
                            if (lhsPkg.mExtras instanceof PackageSetting
                                    && rhsPkg.mExtras instanceof PackageSetting) {
                                final PackageSetting lhsPs = (PackageSetting) lhsPkg.mExtras;
                                final PackageSetting rhsPs = (PackageSetting) rhsPkg.mExtras;
                                if (lhsPs.firstInstallTime > rhsPs.firstInstallTime) {
                                    return 1;
                                } else {
                                    return -1;
                                }
                            } else {
                                return 0;
                            }
                        }
                    }
                });
            }
        }

        if (packagesToDelete != null) {
            final int packageCount = packagesToDelete.size();
            for (int i = 0; i < packageCount; i++) {
                final String packageToDelete = packagesToDelete.get(i);
                if (mService.deletePackageX(packageToDelete, PackageManager.VERSION_CODE_HIGHEST,
                        UserHandle.USER_SYSTEM, PackageManager.DELETE_ALL_USERS)
                                == PackageManager.DELETE_SUCCEEDED) {
                    if (file.getUsableSpace() >= neededSpace) {
                        return true;
                    }
                }
            }
        }

        // Prune uninstalled instant apps
        synchronized (mService.mPackages) {
            // TODO: Track last used time for uninstalled instant apps for better pruning
            for (int userId : UserManagerService.getInstance().getUserIds()) {
                // Prune in-memory state
                removeUninstalledInstantAppStateLPw((UninstalledInstantAppState state) -> {
                    final long elapsedCachingMillis = System.currentTimeMillis() - state.mTimestamp;
                return (elapsedCachingMillis > maxCacheDurationMillis);
                    return (elapsedCachingMillis > maxUninstalledCacheDuration);
                }, userId);

                // Prune on-disk state
@@ -570,12 +725,18 @@ class InstantAppRegistry {

                    final long elapsedCachingMillis = System.currentTimeMillis()
                            - metadataFile.lastModified();
                if (elapsedCachingMillis > maxCacheDurationMillis) {
                    if (elapsedCachingMillis > maxUninstalledCacheDuration) {
                        deleteDir(instantDir);
                        if (file.getUsableSpace() >= neededSpace) {
                            return true;
                        }
                    }
                }
            }
        }

        return false;
    }

    private @Nullable List<InstantAppInfo> getInstalledInstantApplicationsLPr(
            @UserIdInt int userId) {
Loading