summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/core/java/com/android/server/pm/InstallPackageHelper.java48
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerServiceUtils.java19
-rw-r--r--services/core/java/com/android/server/pm/PackageSetting.java16
-rw-r--r--services/core/java/com/android/server/pm/ScanPackageUtils.java3
-rw-r--r--services/core/java/com/android/server/pm/Settings.java7
-rw-r--r--services/core/java/com/android/server/pm/pkg/PackageState.java8
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerSettingsTests.java19
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);