diff --git a/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java b/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java
index 8b86a16075e9d..a65b6815f8adc 100644
--- a/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java
+++ b/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java
@@ -378,6 +378,30 @@ public class FrameworkParsingPackageUtils {
}
}
+ /**
+ * Computes the maxSdkVersion. If the package is not compatible with this platform, populates
+ * {@code outError[0]} with an error message.
+ *
+ * {@code maxVers} is compared against {@code platformSdkVersion}. If {@code maxVers} is less
+ * than the {@code platformSdkVersion} then populates {@code outError[0]} with an error message.
+ * Otherwise, it returns {@code maxVers} unmodified.
+ *
+ * @param maxVers maxSdkVersion number, if specified in the application manifest, or {@code
+ * Integer.MAX_VALUE} otherwise
+ * @param platformSdkVersion platform SDK version number, typically Build.VERSION.SDK_INT
+ * @return the maxSdkVersion that was recognised or an error if the condition is not satisfied
+ */
+ public static ParseResult computeMaxSdkVersion(@IntRange(from = 0) int maxVers,
+ @IntRange(from = 1) int platformSdkVersion, @NonNull ParseInput input) {
+ if (platformSdkVersion > maxVers) {
+ return input.error(PackageManager.INSTALL_FAILED_NEWER_SDK,
+ "Requires max SDK version " + maxVers + " but is "
+ + platformSdkVersion);
+ } else {
+ return input.success(maxVers);
+ }
+ }
+
/**
* Matches a given {@code targetCode} against a set of release codeNames. Target codes can
* either be of the form {@code [codename]}" (e.g {@code "Q"}) or of the form {@code
diff --git a/services/core/java/com/android/server/pm/InitAndSystemPackageHelper.java b/services/core/java/com/android/server/pm/InitAndSystemPackageHelper.java
index 6dbe9b6f89f68..8d7762410b274 100644
--- a/services/core/java/com/android/server/pm/InitAndSystemPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InitAndSystemPackageHelper.java
@@ -30,6 +30,7 @@ import static com.android.server.pm.PackageManagerService.SCAN_NO_DEX;
import static com.android.server.pm.PackageManagerService.SCAN_REQUIRE_KNOWN;
import static com.android.server.pm.PackageManagerService.SYSTEM_PARTITIONS;
import static com.android.server.pm.PackageManagerService.TAG;
+import static com.android.server.pm.pkg.parsing.ParsingPackageUtils.PARSE_CHECK_MAX_SDK_VERSION;
import android.annotation.Nullable;
import android.content.pm.parsing.ApkLiteParseUtils;
@@ -313,10 +314,14 @@ final class InitAndSystemPackageHelper {
@GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
private void scanDirTracedLI(File scanDir, List frameworkSplits,
- final int parseFlags, int scanFlags,
+ int parseFlags, int scanFlags,
long currentTime, PackageParser2 packageParser, ExecutorService executorService) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanDir [" + scanDir.getAbsolutePath() + "]");
try {
+ if ((scanFlags & SCAN_AS_APK_IN_APEX) != 0) {
+ // when scanning apk in apexes, we want to check the maxSdkVersion
+ parseFlags |= PARSE_CHECK_MAX_SDK_VERSION;
+ }
mInstallPackageHelper.installPackagesFromDir(scanDir, frameworkSplits, parseFlags,
scanFlags, currentTime, packageParser, executorService);
} finally {
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java
index f6f9faf98c40a..3893f919c26b0 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java
@@ -305,6 +305,8 @@ public interface ParsingPackage extends ParsingPackageRead {
ParsingPackage setMinSdkVersion(int minSdkVersion);
+ ParsingPackage setMaxSdkVersion(int maxSdkVersion);
+
ParsingPackage setNetworkSecurityConfigRes(int networkSecurityConfigRes);
ParsingPackage setNonLocalizedLabel(CharSequence nonLocalizedLabel);
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageImpl.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageImpl.java
index 67670272ef8b0..ca7282847197b 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageImpl.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageImpl.java
@@ -383,6 +383,7 @@ public class ParsingPackageImpl implements ParsingPackage, ParsingPackageHidden,
@Nullable
private SparseIntArray minExtensionVersions;
private int minSdkVersion = ParsingUtils.DEFAULT_MIN_SDK_VERSION;
+ private int maxSdkVersion = ParsingUtils.DEFAULT_MAX_SDK_VERSION;
private int networkSecurityConfigRes;
@Nullable
private CharSequence nonLocalizedLabel;
@@ -1308,6 +1309,7 @@ public class ParsingPackageImpl implements ParsingPackage, ParsingPackageHidden,
dest.writeFloat(this.maxAspectRatio);
dest.writeFloat(this.minAspectRatio);
dest.writeInt(this.minSdkVersion);
+ dest.writeInt(this.maxSdkVersion);
dest.writeInt(this.networkSecurityConfigRes);
dest.writeCharSequence(this.nonLocalizedLabel);
dest.writeString(this.permission);
@@ -1456,6 +1458,7 @@ public class ParsingPackageImpl implements ParsingPackage, ParsingPackageHidden,
this.maxAspectRatio = in.readFloat();
this.minAspectRatio = in.readFloat();
this.minSdkVersion = in.readInt();
+ this.maxSdkVersion = in.readInt();
this.networkSecurityConfigRes = in.readInt();
this.nonLocalizedLabel = in.readCharSequence();
this.permission = in.readString();
@@ -2069,6 +2072,11 @@ public class ParsingPackageImpl implements ParsingPackage, ParsingPackageHidden,
return minSdkVersion;
}
+ @Override
+ public int getMaxSdkVersion() {
+ return maxSdkVersion;
+ }
+
@Override
public int getNetworkSecurityConfigRes() {
return networkSecurityConfigRes;
@@ -2603,6 +2611,12 @@ public class ParsingPackageImpl implements ParsingPackage, ParsingPackageHidden,
return this;
}
+ @Override
+ public ParsingPackageImpl setMaxSdkVersion(int value) {
+ maxSdkVersion = value;
+ return this;
+ }
+
@Override
public ParsingPackageImpl setNetworkSecurityConfigRes(int value) {
networkSecurityConfigRes = value;
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
index 3eaca9dddcc41..f51ac263a97cc 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
@@ -209,6 +209,8 @@ public class ParsingPackageUtils {
public static final int SDK_VERSION = Build.VERSION.SDK_INT;
public static final String[] SDK_CODENAMES = Build.VERSION.ACTIVE_CODENAMES;
+ public static final String[] PREVIOUS_CODENAMES =
+ Build.VERSION.KNOWN_CODENAMES.toArray(new String[]{});
public static boolean sCompatibilityModeEnabled = true;
public static boolean sUseRoundIcon = false;
@@ -236,6 +238,7 @@ public class ParsingPackageUtils {
*/
public static final int PARSE_IGNORE_OVERLAY_REQUIRED_SYSTEM_PROPERTY = 1 << 7;
public static final int PARSE_FRAMEWORK_RES_SPLITS = 1 << 8;
+ public static final int PARSE_CHECK_MAX_SDK_VERSION = 1 << 9;
public static final int PARSE_CHATTY = 1 << 31;
@@ -1004,7 +1007,7 @@ public class ParsingPackageUtils {
case TAG_FEATURE_GROUP:
return parseFeatureGroup(input, pkg, res, parser);
case TAG_USES_SDK:
- return parseUsesSdk(input, pkg, res, parser);
+ return parseUsesSdk(input, pkg, res, parser, flags);
case TAG_SUPPORT_SCREENS:
return parseSupportScreens(input, pkg, res, parser);
case TAG_PROTECTED_BROADCAST:
@@ -1516,15 +1519,17 @@ public class ParsingPackageUtils {
}
private static ParseResult parseUsesSdk(ParseInput input,
- ParsingPackage pkg, Resources res, XmlResourceParser parser)
+ ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags)
throws IOException, XmlPullParserException {
if (SDK_VERSION > 0) {
+ final boolean checkMaxSdkVersion = (flags & PARSE_CHECK_MAX_SDK_VERSION) != 0;
TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestUsesSdk);
try {
int minVers = ParsingUtils.DEFAULT_MIN_SDK_VERSION;
String minCode = null;
int targetVers = ParsingUtils.DEFAULT_TARGET_SDK_VERSION;
String targetCode = null;
+ int maxVers = Integer.MAX_VALUE;
TypedValue val = sa.peekValue(R.styleable.AndroidManifestUsesSdk_minSdkVersion);
if (val != null) {
@@ -1552,6 +1557,14 @@ public class ParsingPackageUtils {
targetCode = minCode;
}
+ if (checkMaxSdkVersion) {
+ val = sa.peekValue(R.styleable.AndroidManifestUsesSdk_maxSdkVersion);
+ if (val != null) {
+ // maxSdkVersion only supports integer
+ maxVers = val.data;
+ }
+ }
+
ParseResult targetSdkVersionResult = FrameworkParsingPackageUtils
.computeTargetSdkVersion(targetVers, targetCode, SDK_CODENAMES, input);
if (targetSdkVersionResult.isError()) {
@@ -1576,6 +1589,15 @@ public class ParsingPackageUtils {
pkg.setMinSdkVersion(minSdkVersion)
.setTargetSdkVersion(targetSdkVersion);
+ if (checkMaxSdkVersion) {
+ ParseResult maxSdkVersionResult = FrameworkParsingPackageUtils
+ .computeMaxSdkVersion(maxVers, SDK_VERSION, input);
+ if (maxSdkVersionResult.isError()) {
+ return input.error(maxSdkVersionResult);
+ }
+ int maxSdkVersion = maxSdkVersionResult.getResult();
+ pkg.setMaxSdkVersion(maxSdkVersion);
+ }
int type;
final int innerDepth = parser.getDepth();
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingUtils.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingUtils.java
index cb474df8b4690..07512855d2767 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingUtils.java
@@ -50,6 +50,7 @@ public class ParsingUtils {
public static final String ANDROID_RES_NAMESPACE = "http://schemas.android.com/apk/res/android";
public static final int DEFAULT_MIN_SDK_VERSION = 1;
+ public static final int DEFAULT_MAX_SDK_VERSION = Integer.MAX_VALUE;
public static final int DEFAULT_TARGET_SDK_VERSION = 0;
public static final int NOT_SET = -1;
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/PkgWithoutStateAppInfo.java b/services/core/java/com/android/server/pm/pkg/parsing/PkgWithoutStateAppInfo.java
index 3205b76d6dadf..99bcdb964c2f4 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/PkgWithoutStateAppInfo.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/PkgWithoutStateAppInfo.java
@@ -249,6 +249,11 @@ public interface PkgWithoutStateAppInfo {
*/
int getMinSdkVersion();
+ /**
+ * @see R.styleable#AndroidManifestUsesSdk_maxSdkVersion
+ */
+ int getMaxSdkVersion();
+
/**
* @see ApplicationInfo#getNativeHeapZeroInitialized()
* @see R.styleable#AndroidManifestApplication_nativeHeapZeroInitialized