Loading core/java/android/content/pm/PackageParser.java +156 −56 Original line number Diff line number Diff line Loading @@ -1621,7 +1621,7 @@ public class PackageParser { } final AttributeSet attrs = parser; return parseApkLite(apkPath, parser, attrs, signingDetails); return parseApkLite(apkPath, parser, attrs, signingDetails, flags); } catch (XmlPullParserException | IOException | RuntimeException e) { Slog.w(TAG, "Failed to parse " + apkPath, e); Loading Loading @@ -1708,7 +1708,7 @@ public class PackageParser { } private static ApkLite parseApkLite(String codePath, XmlPullParser parser, AttributeSet attrs, SigningDetails signingDetails) SigningDetails signingDetails, int flags) throws IOException, XmlPullParserException, PackageParserException { final Pair<String, String> packageSplit = parsePackageSplitNames(parser, attrs); Loading @@ -1716,11 +1716,12 @@ public class PackageParser { int versionCode = 0; int versionCodeMajor = 0; int revisionCode = 0; int targetSdkVersion = 0; boolean coreApp = false; boolean debuggable = false; boolean multiArch = false; boolean use32bitAbi = false; boolean extractNativeLibs = true; Boolean extractNativeLibsProvided = null; boolean isolatedSplits = false; boolean isFeatureSplit = false; boolean isSplitRequired = false; Loading Loading @@ -1785,7 +1786,8 @@ public class PackageParser { use32bitAbi = attrs.getAttributeBooleanValue(i, false); } if ("extractNativeLibs".equals(attr)) { extractNativeLibs = attrs.getAttributeBooleanValue(i, true); extractNativeLibsProvided = Boolean.valueOf( attrs.getAttributeBooleanValue(i, true)); } if ("preferCodeIntegrity".equals(attr)) { preferCodeIntegrity = attrs.getAttributeBooleanValue(i, false); Loading @@ -1803,8 +1805,50 @@ public class PackageParser { PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, "<uses-split> tag requires 'android:name' attribute"); } } else if (TAG_USES_SDK.equals(parser.getName())) { final String[] errorMsg = new String[1]; Pair<Integer, Integer> versions = deriveSdkVersions(new AbstractVersionsAccessor() { @Override public String getMinSdkVersionCode() { return getAttributeAsString("minSdkVersion"); } @Override public int getMinSdkVersion() { return getAttributeAsInt("minSdkVersion"); } @Override public String getTargetSdkVersionCode() { return getAttributeAsString("targetSdkVersion"); } @Override public int getTargetSdkVersion() { return getAttributeAsInt("targetSdkVersion"); } private String getAttributeAsString(String name) { return attrs.getAttributeValue(ANDROID_RESOURCES, name); } private int getAttributeAsInt(String name) { try { return attrs.getAttributeIntValue(ANDROID_RESOURCES, name, -1); } catch (NumberFormatException e) { return -1; } } }, flags, errorMsg); if (versions == null) { throw new PackageParserException( PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, errorMsg[0]); } targetSdkVersion = versions.second; } } final boolean extractNativeLibsDefault = targetSdkVersion < Build.VERSION_CODES.Q; final boolean extractNativeLibs = (extractNativeLibsProvided != null) ? extractNativeLibsProvided : extractNativeLibsDefault; if (preferCodeIntegrity && extractNativeLibs) { throw new PackageParserException( Loading Loading @@ -2215,65 +2259,60 @@ public class PackageParser { } else if (tagName.equals(TAG_USES_SDK)) { if (SDK_VERSION > 0) { sa = res.obtainAttributes(parser, com.android.internal.R.styleable.AndroidManifestUsesSdk); sa = res.obtainAttributes(parser, R.styleable.AndroidManifestUsesSdk); final TypedArray saFinal = sa; Pair<Integer, Integer> versions = deriveSdkVersions( new AbstractVersionsAccessor() { @Override public String getMinSdkVersionCode() { return getAttributeAsString( R.styleable.AndroidManifestUsesSdk_minSdkVersion); } int minVers = 1; String minCode = null; int targetVers = 0; String targetCode = null; @Override public int getMinSdkVersion() { return getAttributeAsInt( R.styleable.AndroidManifestUsesSdk_minSdkVersion); } TypedValue val = sa.peekValue( com.android.internal.R.styleable.AndroidManifestUsesSdk_minSdkVersion); if (val != null) { if (val.type == TypedValue.TYPE_STRING && val.string != null) { minCode = val.string.toString(); } else { // If it's not a string, it's an integer. minVers = val.data; @Override public String getTargetSdkVersionCode() { return getAttributeAsString( R.styleable.AndroidManifestUsesSdk_targetSdkVersion); } @Override public int getTargetSdkVersion() { return getAttributeAsInt( R.styleable.AndroidManifestUsesSdk_targetSdkVersion); } val = sa.peekValue( com.android.internal.R.styleable.AndroidManifestUsesSdk_targetSdkVersion); if (val != null) { if (val.type == TypedValue.TYPE_STRING && val.string != null) { targetCode = val.string.toString(); if (minCode == null) { minCode = targetCode; private String getAttributeAsString(int index) { TypedValue val = saFinal.peekValue(index); if (val != null && val.type == TypedValue.TYPE_STRING && val.string != null) { return val.string.toString(); } } else { return null; } private int getAttributeAsInt(int index) { TypedValue val = saFinal.peekValue(index); if (val != null && val.type != TypedValue.TYPE_STRING) { // If it's not a string, it's an integer. targetVers = val.data; return val.data; } } else { targetVers = minVers; targetCode = minCode; return -1; } }, flags, outError); sa.recycle(); final int minSdkVersion = PackageParser.computeMinSdkVersion(minVers, minCode, SDK_VERSION, SDK_CODENAMES, outError); if (minSdkVersion < 0) { if (versions == null) { mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK; return null; } boolean defaultToCurrentDevBranch = (flags & PARSE_FORCE_SDK) != 0; final int targetSdkVersion = PackageParser.computeTargetSdkVersion(targetVers, targetCode, SDK_CODENAMES, outError, defaultToCurrentDevBranch); if (targetSdkVersion < 0) { mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK; return null; } pkg.applicationInfo.minSdkVersion = versions.first; pkg.applicationInfo.targetSdkVersion = versions.second; pkg.applicationInfo.minSdkVersion = minSdkVersion; pkg.applicationInfo.targetSdkVersion = targetSdkVersion; sa.recycle(); } XmlUtils.skipCurrentTag(parser); } else if (tagName.equals(TAG_SUPPORT_SCREENS)) { sa = res.obtainAttributes(parser, com.android.internal.R.styleable.AndroidManifestSupportsScreens); Loading Loading @@ -2675,6 +2714,67 @@ public class PackageParser { return -1; } private interface AbstractVersionsAccessor { /** Returns minimum SDK version code string, or null if absent. */ String getMinSdkVersionCode(); /** Returns minimum SDK version code, or -1 if absent. */ int getMinSdkVersion(); /** Returns target SDK version code string, or null if absent. */ String getTargetSdkVersionCode(); /** Returns target SDK version code, or -1 if absent. */ int getTargetSdkVersion(); } private static @Nullable Pair<Integer, Integer> deriveSdkVersions( @NonNull AbstractVersionsAccessor accessor, int flags, String[] outError) { int minVers = 1; String minCode = null; int targetVers = 0; String targetCode = null; String code = accessor.getMinSdkVersionCode(); int version = accessor.getMinSdkVersion(); // Check integer first since code is almost never a null string (e.g. "28"). if (version >= 0) { minVers = version; } else if (code != null) { minCode = code; } code = accessor.getTargetSdkVersionCode(); version = accessor.getTargetSdkVersion(); // Check integer first since code is almost never a null string (e.g. "28"). if (version >= 0) { targetVers = version; } else if (code != null) { targetCode = code; if (minCode == null) { minCode = targetCode; } } else { targetVers = minVers; targetCode = minCode; } final int minSdkVersion = computeMinSdkVersion(minVers, minCode, SDK_VERSION, SDK_CODENAMES, outError); if (minSdkVersion < 0) { return null; } boolean defaultToCurrentDevBranch = (flags & PARSE_FORCE_SDK) != 0; final int targetSdkVersion = computeTargetSdkVersion(targetVers, targetCode, SDK_CODENAMES, outError, defaultToCurrentDevBranch); if (targetSdkVersion < 0) { return null; } return Pair.create(minSdkVersion, targetSdkVersion); } /** * Computes the minSdkVersion to use at runtime. If the package is not * compatible with this platform, populates {@code outError[0]} with an Loading Loading
core/java/android/content/pm/PackageParser.java +156 −56 Original line number Diff line number Diff line Loading @@ -1621,7 +1621,7 @@ public class PackageParser { } final AttributeSet attrs = parser; return parseApkLite(apkPath, parser, attrs, signingDetails); return parseApkLite(apkPath, parser, attrs, signingDetails, flags); } catch (XmlPullParserException | IOException | RuntimeException e) { Slog.w(TAG, "Failed to parse " + apkPath, e); Loading Loading @@ -1708,7 +1708,7 @@ public class PackageParser { } private static ApkLite parseApkLite(String codePath, XmlPullParser parser, AttributeSet attrs, SigningDetails signingDetails) SigningDetails signingDetails, int flags) throws IOException, XmlPullParserException, PackageParserException { final Pair<String, String> packageSplit = parsePackageSplitNames(parser, attrs); Loading @@ -1716,11 +1716,12 @@ public class PackageParser { int versionCode = 0; int versionCodeMajor = 0; int revisionCode = 0; int targetSdkVersion = 0; boolean coreApp = false; boolean debuggable = false; boolean multiArch = false; boolean use32bitAbi = false; boolean extractNativeLibs = true; Boolean extractNativeLibsProvided = null; boolean isolatedSplits = false; boolean isFeatureSplit = false; boolean isSplitRequired = false; Loading Loading @@ -1785,7 +1786,8 @@ public class PackageParser { use32bitAbi = attrs.getAttributeBooleanValue(i, false); } if ("extractNativeLibs".equals(attr)) { extractNativeLibs = attrs.getAttributeBooleanValue(i, true); extractNativeLibsProvided = Boolean.valueOf( attrs.getAttributeBooleanValue(i, true)); } if ("preferCodeIntegrity".equals(attr)) { preferCodeIntegrity = attrs.getAttributeBooleanValue(i, false); Loading @@ -1803,8 +1805,50 @@ public class PackageParser { PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, "<uses-split> tag requires 'android:name' attribute"); } } else if (TAG_USES_SDK.equals(parser.getName())) { final String[] errorMsg = new String[1]; Pair<Integer, Integer> versions = deriveSdkVersions(new AbstractVersionsAccessor() { @Override public String getMinSdkVersionCode() { return getAttributeAsString("minSdkVersion"); } @Override public int getMinSdkVersion() { return getAttributeAsInt("minSdkVersion"); } @Override public String getTargetSdkVersionCode() { return getAttributeAsString("targetSdkVersion"); } @Override public int getTargetSdkVersion() { return getAttributeAsInt("targetSdkVersion"); } private String getAttributeAsString(String name) { return attrs.getAttributeValue(ANDROID_RESOURCES, name); } private int getAttributeAsInt(String name) { try { return attrs.getAttributeIntValue(ANDROID_RESOURCES, name, -1); } catch (NumberFormatException e) { return -1; } } }, flags, errorMsg); if (versions == null) { throw new PackageParserException( PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, errorMsg[0]); } targetSdkVersion = versions.second; } } final boolean extractNativeLibsDefault = targetSdkVersion < Build.VERSION_CODES.Q; final boolean extractNativeLibs = (extractNativeLibsProvided != null) ? extractNativeLibsProvided : extractNativeLibsDefault; if (preferCodeIntegrity && extractNativeLibs) { throw new PackageParserException( Loading Loading @@ -2215,65 +2259,60 @@ public class PackageParser { } else if (tagName.equals(TAG_USES_SDK)) { if (SDK_VERSION > 0) { sa = res.obtainAttributes(parser, com.android.internal.R.styleable.AndroidManifestUsesSdk); sa = res.obtainAttributes(parser, R.styleable.AndroidManifestUsesSdk); final TypedArray saFinal = sa; Pair<Integer, Integer> versions = deriveSdkVersions( new AbstractVersionsAccessor() { @Override public String getMinSdkVersionCode() { return getAttributeAsString( R.styleable.AndroidManifestUsesSdk_minSdkVersion); } int minVers = 1; String minCode = null; int targetVers = 0; String targetCode = null; @Override public int getMinSdkVersion() { return getAttributeAsInt( R.styleable.AndroidManifestUsesSdk_minSdkVersion); } TypedValue val = sa.peekValue( com.android.internal.R.styleable.AndroidManifestUsesSdk_minSdkVersion); if (val != null) { if (val.type == TypedValue.TYPE_STRING && val.string != null) { minCode = val.string.toString(); } else { // If it's not a string, it's an integer. minVers = val.data; @Override public String getTargetSdkVersionCode() { return getAttributeAsString( R.styleable.AndroidManifestUsesSdk_targetSdkVersion); } @Override public int getTargetSdkVersion() { return getAttributeAsInt( R.styleable.AndroidManifestUsesSdk_targetSdkVersion); } val = sa.peekValue( com.android.internal.R.styleable.AndroidManifestUsesSdk_targetSdkVersion); if (val != null) { if (val.type == TypedValue.TYPE_STRING && val.string != null) { targetCode = val.string.toString(); if (minCode == null) { minCode = targetCode; private String getAttributeAsString(int index) { TypedValue val = saFinal.peekValue(index); if (val != null && val.type == TypedValue.TYPE_STRING && val.string != null) { return val.string.toString(); } } else { return null; } private int getAttributeAsInt(int index) { TypedValue val = saFinal.peekValue(index); if (val != null && val.type != TypedValue.TYPE_STRING) { // If it's not a string, it's an integer. targetVers = val.data; return val.data; } } else { targetVers = minVers; targetCode = minCode; return -1; } }, flags, outError); sa.recycle(); final int minSdkVersion = PackageParser.computeMinSdkVersion(minVers, minCode, SDK_VERSION, SDK_CODENAMES, outError); if (minSdkVersion < 0) { if (versions == null) { mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK; return null; } boolean defaultToCurrentDevBranch = (flags & PARSE_FORCE_SDK) != 0; final int targetSdkVersion = PackageParser.computeTargetSdkVersion(targetVers, targetCode, SDK_CODENAMES, outError, defaultToCurrentDevBranch); if (targetSdkVersion < 0) { mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK; return null; } pkg.applicationInfo.minSdkVersion = versions.first; pkg.applicationInfo.targetSdkVersion = versions.second; pkg.applicationInfo.minSdkVersion = minSdkVersion; pkg.applicationInfo.targetSdkVersion = targetSdkVersion; sa.recycle(); } XmlUtils.skipCurrentTag(parser); } else if (tagName.equals(TAG_SUPPORT_SCREENS)) { sa = res.obtainAttributes(parser, com.android.internal.R.styleable.AndroidManifestSupportsScreens); Loading Loading @@ -2675,6 +2714,67 @@ public class PackageParser { return -1; } private interface AbstractVersionsAccessor { /** Returns minimum SDK version code string, or null if absent. */ String getMinSdkVersionCode(); /** Returns minimum SDK version code, or -1 if absent. */ int getMinSdkVersion(); /** Returns target SDK version code string, or null if absent. */ String getTargetSdkVersionCode(); /** Returns target SDK version code, or -1 if absent. */ int getTargetSdkVersion(); } private static @Nullable Pair<Integer, Integer> deriveSdkVersions( @NonNull AbstractVersionsAccessor accessor, int flags, String[] outError) { int minVers = 1; String minCode = null; int targetVers = 0; String targetCode = null; String code = accessor.getMinSdkVersionCode(); int version = accessor.getMinSdkVersion(); // Check integer first since code is almost never a null string (e.g. "28"). if (version >= 0) { minVers = version; } else if (code != null) { minCode = code; } code = accessor.getTargetSdkVersionCode(); version = accessor.getTargetSdkVersion(); // Check integer first since code is almost never a null string (e.g. "28"). if (version >= 0) { targetVers = version; } else if (code != null) { targetCode = code; if (minCode == null) { minCode = targetCode; } } else { targetVers = minVers; targetCode = minCode; } final int minSdkVersion = computeMinSdkVersion(minVers, minCode, SDK_VERSION, SDK_CODENAMES, outError); if (minSdkVersion < 0) { return null; } boolean defaultToCurrentDevBranch = (flags & PARSE_FORCE_SDK) != 0; final int targetSdkVersion = computeTargetSdkVersion(targetVers, targetCode, SDK_CODENAMES, outError, defaultToCurrentDevBranch); if (targetSdkVersion < 0) { return null; } return Pair.create(minSdkVersion, targetSdkVersion); } /** * Computes the minSdkVersion to use at runtime. If the package is not * compatible with this platform, populates {@code outError[0]} with an Loading