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

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

Merge "[PM] Add downgrade check for archived app and DELETE_KEEP_DATA" into main

parents c52ed01e 23828152
Loading
Loading
Loading
Loading
+39 −9
Original line number Diff line number Diff line
@@ -2629,18 +2629,28 @@ final class InstallPackageHelper {

        String packageName = pkgLite.packageName;
        synchronized (mPm.mLock) {
            // Package which currently owns the data that the new package will own if installed.
            // If an app is uninstalled while keeping data (e.g. adb uninstall -k), installedPkg
            // will be null whereas dataOwnerPkg will contain information about the package
            // which was uninstalled while keeping its data.
            AndroidPackage dataOwnerPkg = mPm.mPackages.get(packageName);
            PackageSetting dataOwnerPs = mPm.mSettings.getPackageLPr(packageName);
            if (dataOwnerPkg  == null) {
                if (dataOwnerPs != null) {
                    dataOwnerPkg = dataOwnerPs.getPkg();
            if (dataOwnerPs == null) {
                if (requiredInstalledVersionCode != PackageManager.VERSION_CODE_HIGHEST) {
                    String errorMsg = "Required installed version code was "
                            + requiredInstalledVersionCode
                            + " but package is not installed";
                    Slog.w(TAG, errorMsg);
                    return Pair.create(
                            PackageManager.INSTALL_FAILED_WRONG_INSTALLED_VERSION, errorMsg);
                }
                // The package doesn't exist in the system, don't need to check the version
                // replacing.
                return Pair.create(PackageManager.INSTALL_SUCCEEDED, null);
            }

            // Package which currently owns the data that the new package will own if installed.
            // If an app is uninstalled while keeping data (e.g. adb uninstall -k), dataOwnerPkg
            // will be null whereas dataOwnerPs will contain information about the package
            // which was uninstalled while keeping its data. The AndroidPackage object that the
            // PackageSetting refers to is the same object that is stored in mPackages.
            AndroidPackage dataOwnerPkg = dataOwnerPs.getPkg();

            if (requiredInstalledVersionCode != PackageManager.VERSION_CODE_HIGHEST) {
                if (dataOwnerPkg == null) {
                    String errorMsg = "Required installed version code was "
@@ -2662,7 +2672,27 @@ final class InstallPackageHelper {
                }
            }

            if (dataOwnerPkg != null && !dataOwnerPkg.isSdkLibrary()) {
            // If dataOwnerPkg is null but dataOwnerPs is not null, there is always data on
            // some users. Wwe should do the downgrade check. E.g. DELETE_KEEP_DATA and
            // archived apps
            if (dataOwnerPkg == null) {
                if (!PackageManagerServiceUtils.isDowngradePermitted(installFlags,
                        dataOwnerPs.isDebuggable())) {
                    // The data exists on some users and downgrade is not permitted; a lower
                    // version of the app will not be allowed.
                    try {
                        PackageManagerServiceUtils.checkDowngrade(dataOwnerPs, pkgLite);
                    } catch (PackageManagerException e) {
                        String errorMsg = "Downgrade detected on app uninstalled with"
                                + " DELETE_KEEP_DATA: " + e.getMessage();
                        Slog.w(TAG, errorMsg);
                        return Pair.create(
                                PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE, errorMsg);
                    }
                }
                // dataOwnerPs.getPkg() is not null on system apps case. Don't need to consider
                // system apps case like below.
            } else if (dataOwnerPkg != null && !dataOwnerPkg.isSdkLibrary()) {
                if (!PackageManagerServiceUtils.isDowngradePermitted(installFlags,
                        dataOwnerPkg.isDebuggable())) {
                    // Downgrade is not permitted; a lower version of the app will not be allowed
+16 −3
Original line number Diff line number Diff line
@@ -1419,10 +1419,23 @@ public class PackageManagerServiceUtils {

    /**
     * Check and throw if the given before/after packages would be considered a
     * downgrade.
     * downgrade with {@link PackageSetting}.
     */
    public static void checkDowngrade(AndroidPackage before, PackageInfoLite after)
            throws PackageManagerException {
    public static void checkDowngrade(@NonNull PackageSetting before,
            @NonNull PackageInfoLite after) throws PackageManagerException {
        if (after.getLongVersionCode() < before.getVersionCode()) {
            throw new PackageManagerException(INSTALL_FAILED_VERSION_DOWNGRADE,
                    "Update version code " + after.versionCode + " is older than current "
                            + before.getVersionCode());
        }
    }

    /**
     * Check and throw if the given before/after packages would be considered a
     * downgrade with {@link AndroidPackage}.
     */
    public static void checkDowngrade(@NonNull AndroidPackage before,
            @NonNull PackageInfoLite after) throws PackageManagerException {
        if (after.getLongVersionCode() < before.getLongVersionCode()) {
            throw new PackageManagerException(INSTALL_FAILED_VERSION_DOWNGRADE,
                    "Update version code " + after.versionCode + " is older than current "
+16 −0
Original line number Diff line number Diff line
@@ -97,6 +97,7 @@ public class PackageSetting extends SettingBase implements PackageStateInternal
                FORCE_QUERYABLE_OVERRIDE,
                SCANNED_AS_STOPPED_SYSTEM_APP,
                PENDING_RESTORE,
                DEBUGGABLE,
        })
        public @interface Flags {
        }
@@ -105,6 +106,7 @@ public class PackageSetting extends SettingBase implements PackageStateInternal
        private static final int FORCE_QUERYABLE_OVERRIDE = 1 << 2;
        private static final int SCANNED_AS_STOPPED_SYSTEM_APP = 1 << 3;
        private static final int PENDING_RESTORE = 1 << 4;
        private static final int DEBUGGABLE = 1 << 5;
    }
    private int mBooleans;

@@ -562,6 +564,20 @@ public class PackageSetting extends SettingBase implements PackageStateInternal
        return getBoolean(Booleans.PENDING_RESTORE);
    }

    /**
     * @see PackageState#isDebuggable
     */
    public PackageSetting setDebuggable(boolean value) {
        setBoolean(Booleans.DEBUGGABLE, value);
        onChanged();
        return this;
    }

    @Override
    public boolean isDebuggable() {
        return getBoolean(Booleans.DEBUGGABLE);
    }

    @Override
    public String toString() {
        return "PackageSetting{"
+3 −0
Original line number Diff line number Diff line
@@ -437,6 +437,9 @@ final class ScanPackageUtils {
            pkgSetting.setIsOrphaned(true);
        }

        // update debuggable to packageSetting
        pkgSetting.setDebuggable(parsedPackage.isDebuggable());

        // Take care of first install / last update times.
        final long scanFileTime = getLastModifiedTime(parsedPackage);
        final long existingFirstInstallTime = userId == UserHandle.USER_ALL
+6 −1
Original line number Diff line number Diff line
@@ -3255,6 +3255,9 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile
        if (pkg.isPendingRestore()) {
            serializer.attributeBoolean(null, "pendingRestore", true);
        }
        if (pkg.isDebuggable()) {
            serializer.attributeBoolean(null, "debuggable", true);
        }
        if (pkg.isLoading()) {
            serializer.attributeBoolean(null, "isLoading", true);
        }
@@ -3269,7 +3272,6 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile
        serializer.attributeInt(null, "appMetadataSource",
                pkg.getAppMetadataSource());


        writeUsesSdkLibLPw(serializer, pkg.getUsesSdkLibraries(),
                pkg.getUsesSdkLibrariesVersionsMajor(), pkg.getUsesSdkLibrariesOptional());

@@ -4059,6 +4061,7 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile
        long versionCode = 0;
        boolean installedForceQueryable = false;
        boolean isPendingRestore = false;
        boolean isDebuggable = false;
        float loadingProgress = 0;
        long loadingCompletedTime = 0;
        UUID domainSetId;
@@ -4085,6 +4088,7 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile
            updateAvailable = parser.getAttributeBoolean(null, "updateAvailable", false);
            installedForceQueryable = parser.getAttributeBoolean(null, "forceQueryable", false);
            isPendingRestore = parser.getAttributeBoolean(null, "pendingRestore", false);
            isDebuggable = parser.getAttributeBoolean(null, "debuggable", false);
            loadingProgress = parser.getAttributeFloat(null, "loadingProgress", 0);
            loadingCompletedTime = parser.getAttributeLongHex(null, "loadingCompletedTime", 0);

@@ -4259,6 +4263,7 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile
                    .setUpdateAvailable(updateAvailable)
                    .setForceQueryableOverride(installedForceQueryable)
                    .setPendingRestore(isPendingRestore)
                    .setDebuggable(isDebuggable)
                    .setLoadingProgress(loadingProgress)
                    .setLoadingCompletedTime(loadingCompletedTime)
                    .setAppMetadataFilePath(appMetadataFilePath)
Loading