diff options
7 files changed, 107 insertions, 13 deletions
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java index 8ee02dc4f901..303371bd9a92 100644 --- a/services/core/java/com/android/server/pm/InstallPackageHelper.java +++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java @@ -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 diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java index 924b36cef79a..c3cac2032a91 100644 --- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java +++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java @@ -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 " diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java index 7870b1735af4..82df527edcc3 100644 --- a/services/core/java/com/android/server/pm/PackageSetting.java +++ b/services/core/java/com/android/server/pm/PackageSetting.java @@ -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{" diff --git a/services/core/java/com/android/server/pm/ScanPackageUtils.java b/services/core/java/com/android/server/pm/ScanPackageUtils.java index 9ab6016f3d57..d8ce38e0cd2c 100644 --- a/services/core/java/com/android/server/pm/ScanPackageUtils.java +++ b/services/core/java/com/android/server/pm/ScanPackageUtils.java @@ -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 diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index 39565526f33e..0d16b009d9a5 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -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) diff --git a/services/core/java/com/android/server/pm/pkg/PackageState.java b/services/core/java/com/android/server/pm/pkg/PackageState.java index e0ee199a343d..58761886ecb9 100644 --- a/services/core/java/com/android/server/pm/pkg/PackageState.java +++ b/services/core/java/com/android/server/pm/pkg/PackageState.java @@ -274,6 +274,14 @@ public interface PackageState { boolean isPendingRestore(); /** + * @see ApplicationInfo#FLAG_DEBUGGABLE + * @see R.styleable#AndroidManifestApplication_debuggable + * @see AndroidPackage#isDebuggable + * @hide + */ + boolean isDebuggable(); + + /** * Retrieves the shared user app ID. Note that the actual shared user data is not available here * and must be queried separately. * diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerSettingsTests.java index 89b4aea216f9..71383069d08a 100644 --- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerSettingsTests.java +++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerSettingsTests.java @@ -1027,6 +1027,25 @@ public class PackageManagerSettingsTests { } @Test + public void testWriteReadDebuggable() { + Settings settings = makeSettings(); + PackageSetting packageSetting = createPackageSetting(PACKAGE_NAME_1); + packageSetting.setAppId(Process.FIRST_APPLICATION_UID); + packageSetting.setPkg(PackageImpl.forTesting(PACKAGE_NAME_1).hideAsParsed() + .setUid(packageSetting.getAppId()) + .hideAsFinal()); + + packageSetting.setDebuggable(true); + settings.mPackages.put(PACKAGE_NAME_1, packageSetting); + + settings.writeLPr(computer, /* sync= */ true); + settings.mPackages.clear(); + + assertThat(settings.readLPw(computer, createFakeUsers()), is(true)); + assertThat(settings.getPackageLPr(PACKAGE_NAME_1).isDebuggable(), is(true)); + } + + @Test public void testWriteReadArchiveState() { Settings settings = makeSettings(); PackageSetting packageSetting = createPackageSetting(PACKAGE_NAME_1); |