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

Commit 39952bb8 authored by Ivan Chiang's avatar Ivan Chiang
Browse files

[PM] Add downgrade check for split apps when data exists

- Add BaseRevisionCode in PackageSetting
- Preserve the related split info downgrade check  when the app is
deleted with keeping data and archived app cases. After the package
is installed successfully, remove the related information to reduce
performance concerns.

Flag: android.content.pm.archiving
Bug: 348131934
Bug: 350851527
Test: atest PackageManagerSettingsTests
Test: atest PackageManagerTest
Test: atest PackageInstallerArchiveTest
Test: atest ArchiveTest
Change-Id: I195b44a31dfd7f14187a8495a8ca2327215e463b
parent a2cf8a5e
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -2261,6 +2261,12 @@ final class InstallPackageHelper {
                        installRequest.getNewUsers());
                mPm.updateSequenceNumberLP(ps, installRequest.getNewUsers());
                mPm.updateInstantAppInstallerLocked(packageName);

                // The installation is success, remove the split info copy stored in package
                // setting for the downgrade version check of DELETE_KEEP_DATA and archived app
                // cases.
                ps.setSplitNames(null);
                ps.setSplitRevisionCodes(null);
            }
            installRequest.onCommitFinished();
        }
+17 −13
Original line number Diff line number Diff line
@@ -1423,11 +1423,8 @@ public class PackageManagerServiceUtils {
     */
    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());
        }
        checkDowngrade(before.getVersionCode(), before.getBaseRevisionCode(),
                before.getSplitNames(), before.getSplitRevisionCodes(), after);
    }

    /**
@@ -1436,28 +1433,35 @@ public class PackageManagerServiceUtils {
     */
    public static void checkDowngrade(@NonNull AndroidPackage before,
            @NonNull PackageInfoLite after) throws PackageManagerException {
        if (after.getLongVersionCode() < before.getLongVersionCode()) {
        checkDowngrade(before.getLongVersionCode(), before.getBaseRevisionCode(),
                before.getSplitNames(), before.getSplitRevisionCodes(), after);
    }

    private static void checkDowngrade(long beforeVersionCode, int beforeBaseRevisionCode,
            @NonNull String[] beforeSplitNames, @NonNull int[] beforeSplitRevisionCodes,
            @NonNull PackageInfoLite after) throws PackageManagerException {
        if (after.getLongVersionCode() < beforeVersionCode) {
            throw new PackageManagerException(INSTALL_FAILED_VERSION_DOWNGRADE,
                    "Update version code " + after.versionCode + " is older than current "
                            + before.getLongVersionCode());
        } else if (after.getLongVersionCode() == before.getLongVersionCode()) {
            if (after.baseRevisionCode < before.getBaseRevisionCode()) {
                            + beforeVersionCode);
        } else if (after.getLongVersionCode() == beforeVersionCode) {
            if (after.baseRevisionCode < beforeBaseRevisionCode) {
                throw new PackageManagerException(INSTALL_FAILED_VERSION_DOWNGRADE,
                        "Update base revision code " + after.baseRevisionCode
                                + " is older than current " + before.getBaseRevisionCode());
                                + " is older than current " + beforeBaseRevisionCode);
            }

            if (!ArrayUtils.isEmpty(after.splitNames)) {
                for (int i = 0; i < after.splitNames.length; i++) {
                    final String splitName = after.splitNames[i];
                    final int j = ArrayUtils.indexOf(before.getSplitNames(), splitName);
                    final int j = ArrayUtils.indexOf(beforeSplitNames, splitName);
                    if (j != -1) {
                        if (after.splitRevisionCodes[i] < before.getSplitRevisionCodes()[j]) {
                        if (after.splitRevisionCodes[i] < beforeSplitRevisionCodes[j]) {
                            throw new PackageManagerException(INSTALL_FAILED_VERSION_DOWNGRADE,
                                    "Update split " + splitName + " revision code "
                                            + after.splitRevisionCodes[i]
                                            + " is older than current "
                                            + before.getSplitRevisionCodes()[j]);
                                            + beforeSplitRevisionCodes[j]);
                        }
                    }
                }
+77 −0
Original line number Diff line number Diff line
@@ -234,6 +234,22 @@ public class PackageSetting extends SettingBase implements PackageStateInternal
    @Nullable
    private byte[] mRestrictUpdateHash;

    // This is the copy of the same data stored in AndroidPackage. It is not null if the
    // AndroidPackage is deleted in cases of DELETE_KEEP_DATA. When AndroidPackage is not null,
    // the field will be null, and the getter method will return the data from AndroidPackage
    // instead.
    @Nullable
    private String[] mSplitNames;

    // This is the copy of the same data stored in AndroidPackage. It is not null if the
    // AndroidPackage is deleted in cases of DELETE_KEEP_DATA. When AndroidPackage is not null,
    // the field will be null, and the getter method will return the data from AndroidPackage
    // instead.
    @Nullable
    private int[] mSplitRevisionCodes;

    private int mBaseRevisionCode;

    /**
     * Snapshot support.
     */
@@ -578,6 +594,62 @@ public class PackageSetting extends SettingBase implements PackageStateInternal
        return getBoolean(Booleans.DEBUGGABLE);
    }

    /**
     * @see AndroidPackage#getBaseRevisionCode
     */
    public PackageSetting setBaseRevisionCode(int value) {
        mBaseRevisionCode = value;
        onChanged();
        return this;
    }

    /**
     * @see AndroidPackage#getBaseRevisionCode
     */
    public int getBaseRevisionCode() {
        return mBaseRevisionCode;
    }

    /**
     * @see AndroidPackage#getSplitNames
     */
    public PackageSetting setSplitNames(String[] value) {
        mSplitNames = value;
        onChanged();
        return this;
    }

    /**
     * @see AndroidPackage#getSplitNames
     */
    @NonNull
    public String[] getSplitNames() {
        if (pkg != null) {
            return pkg.getSplitNames();
        }
        return mSplitNames == null ? EmptyArray.STRING : mSplitNames;
    }

    /**
     * @see AndroidPackage#getSplitRevisionCodes
     */
    public PackageSetting setSplitRevisionCodes(int[] value) {
        mSplitRevisionCodes = value;
        onChanged();
        return this;
    }

    /**
     * @see AndroidPackage#getSplitRevisionCodes
     */
    @NonNull
    public int[] getSplitRevisionCodes() {
        if (pkg != null) {
            return pkg.getSplitRevisionCodes();
        }
        return mSplitRevisionCodes == null ? EmptyArray.INT : mSplitRevisionCodes;
    }

    @Override
    public String toString() {
        return "PackageSetting{"
@@ -739,6 +811,11 @@ public class PackageSetting extends SettingBase implements PackageStateInternal
        mTargetSdkVersion = other.mTargetSdkVersion;
        mRestrictUpdateHash = other.mRestrictUpdateHash == null
                ? null : other.mRestrictUpdateHash.clone();
        mBaseRevisionCode = other.mBaseRevisionCode;
        mSplitNames = other.mSplitNames != null
                ? Arrays.copyOf(other.mSplitNames, other.mSplitNames.length) : null;
        mSplitRevisionCodes = other.mSplitRevisionCodes != null
                ? Arrays.copyOf(other.mSplitRevisionCodes, other.mSplitRevisionCodes.length) : null;

        usesSdkLibraries = other.usesSdkLibraries != null
                ? Arrays.copyOf(other.usesSdkLibraries,
+7 −0
Original line number Diff line number Diff line
@@ -432,6 +432,13 @@ final class RemovePackageHelper {
                }
                deletedPs.setInstalled(/* installed= */ false, userId);
            }

            // Preserve split apk information for downgrade check with DELETE_KEEP_DATA and archived
            // app cases
            if (deletedPkg.getSplitNames() != null) {
                deletedPs.setSplitNames(deletedPkg.getSplitNames());
                deletedPs.setSplitRevisionCodes(deletedPkg.getSplitRevisionCodes());
            }
        }

        // make sure to preserve per-user installed state if this removal was just
+2 −1
Original line number Diff line number Diff line
@@ -437,8 +437,9 @@ final class ScanPackageUtils {
            pkgSetting.setIsOrphaned(true);
        }

        // update debuggable to packageSetting
        // update debuggable and BaseRevisionCode to packageSetting
        pkgSetting.setDebuggable(parsedPackage.isDebuggable());
        pkgSetting.setBaseRevisionCode(parsedPackage.getBaseRevisionCode());

        // Take care of first install / last update times.
        final long scanFileTime = getLastModifiedTime(parsedPackage);
Loading