From e319e3acb5d0ca33402484bedcfb6c323b74d088 Mon Sep 17 00:00:00 2001 From: Winson Date: Fri, 14 May 2021 13:02:22 -0700 Subject: [PATCH] Fix ApkLite attribute parsing Reads properly namespaced attributes only, and always assigns regardless of presence to ensure that last tag is taken, mirroring full parsing. Also fixes targetSdkVersion parsing so that it mirrors the logic used by the full parser. Bug: 184942889 Merged-In: I6c7014e5dae0f6f15268f0271c133879a89f5bc7 Change-Id: I6c7014e5dae0f6f15268f0271c133879a89f5bc7 --- .../content/pm/parsing/ApkLiteParseUtils.java | 222 ++++++++---------- .../pm/parsing/ParsingPackageImpl.java | 4 +- .../pm/parsing/ParsingPackageUtils.java | 8 +- .../content/pm/parsing/ParsingUtils.java | 5 + 4 files changed, 109 insertions(+), 130 deletions(-) diff --git a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java index 5887047728a63..76b98659067fe 100644 --- a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java +++ b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java @@ -19,6 +19,9 @@ package android.content.pm.parsing; import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME; import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; import static android.content.pm.parsing.ParsingPackageUtils.validateName; +import static android.content.pm.parsing.ParsingUtils.ANDROID_RES_NAMESPACE; +import static android.content.pm.parsing.ParsingUtils.DEFAULT_MIN_SDK_VERSION; +import static android.content.pm.parsing.ParsingUtils.DEFAULT_TARGET_SDK_VERSION; import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER; import android.annotation.NonNull; @@ -31,6 +34,7 @@ import android.content.pm.parsing.result.ParseResult; import android.content.res.ApkAssets; import android.content.res.XmlResourceParser; import android.os.Trace; +import android.text.TextUtils; import android.util.ArrayMap; import android.util.AttributeSet; import android.util.Pair; @@ -59,10 +63,6 @@ public class ApkLiteParseUtils { private static final String TAG = ParsingUtils.TAG; - // TODO(b/135203078): Consolidate constants - private static final int DEFAULT_MIN_SDK_VERSION = 1; - private static final int DEFAULT_TARGET_SDK_VERSION = 0; - private static final int PARSE_DEFAULT_INSTALL_LOCATION = PackageInfo.INSTALL_LOCATION_UNSPECIFIED; @@ -323,8 +323,7 @@ public class ApkLiteParseUtils { signingDetails = PackageParser.SigningDetails.UNKNOWN; } - final AttributeSet attrs = parser; - return parseApkLite(input, apkPath, parser, attrs, signingDetails); + return parseApkLite(input, apkPath, parser, signingDetails); } catch (XmlPullParserException | IOException | RuntimeException e) { Slog.w(TAG, "Failed to parse " + apkPath, e); return input.error(PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION, @@ -342,32 +341,39 @@ public class ApkLiteParseUtils { } private static ParseResult parseApkLite(ParseInput input, String codePath, - XmlPullParser parser, AttributeSet attrs, PackageParser.SigningDetails signingDetails) + XmlResourceParser parser, PackageParser.SigningDetails signingDetails) throws IOException, XmlPullParserException { - ParseResult> result = parsePackageSplitNames(input, parser, attrs); + ParseResult> result = parsePackageSplitNames(input, parser); if (result.isError()) { return input.error(result); } Pair packageSplit = result.getResult(); - int installLocation = PARSE_DEFAULT_INSTALL_LOCATION; - int versionCode = 0; - int versionCodeMajor = 0; + int installLocation = parser.getAttributeIntValue(ANDROID_RES_NAMESPACE, + "installLocation", PARSE_DEFAULT_INSTALL_LOCATION); + int versionCode = parser.getAttributeIntValue(ANDROID_RES_NAMESPACE, "versionCode", 0); + int versionCodeMajor = parser.getAttributeIntValue(ANDROID_RES_NAMESPACE, + "versionCodeMajor", + 0); + int revisionCode = parser.getAttributeIntValue(ANDROID_RES_NAMESPACE, "revisionCode", 0); + boolean coreApp = parser.getAttributeBooleanValue("", "coreApp", false); + boolean isolatedSplits = parser.getAttributeBooleanValue(ANDROID_RES_NAMESPACE, + "isolatedSplits", false); + boolean isFeatureSplit = parser.getAttributeBooleanValue(ANDROID_RES_NAMESPACE, + "isFeatureSplit", false); + boolean isSplitRequired = parser.getAttributeBooleanValue(ANDROID_RES_NAMESPACE, + "isSplitRequired", false); + String configForSplit = parser.getAttributeValue(ANDROID_RES_NAMESPACE, "configForSplit"); + int targetSdkVersion = DEFAULT_TARGET_SDK_VERSION; int minSdkVersion = DEFAULT_MIN_SDK_VERSION; - int revisionCode = 0; - boolean coreApp = false; boolean debuggable = false; boolean profilableByShell = false; boolean multiArch = false; boolean use32bitAbi = false; boolean extractNativeLibs = true; - boolean isolatedSplits = false; - boolean isFeatureSplit = false; - boolean isSplitRequired = false; boolean useEmbeddedDex = false; - String configForSplit = null; String usesSplitName = null; String targetPackage = null; boolean overlayIsStatic = false; @@ -377,40 +383,6 @@ public class ApkLiteParseUtils { String requiredSystemPropertyName = null; String requiredSystemPropertyValue = null; - for (int i = 0; i < attrs.getAttributeCount(); i++) { - final String attr = attrs.getAttributeName(i); - switch (attr) { - case "installLocation": - installLocation = attrs.getAttributeIntValue(i, - PARSE_DEFAULT_INSTALL_LOCATION); - break; - case "versionCode": - versionCode = attrs.getAttributeIntValue(i, 0); - break; - case "versionCodeMajor": - versionCodeMajor = attrs.getAttributeIntValue(i, 0); - break; - case "revisionCode": - revisionCode = attrs.getAttributeIntValue(i, 0); - break; - case "coreApp": - coreApp = attrs.getAttributeBooleanValue(i, false); - break; - case "isolatedSplits": - isolatedSplits = attrs.getAttributeBooleanValue(i, false); - break; - case "configForSplit": - configForSplit = attrs.getAttributeValue(i); - break; - case "isFeatureSplit": - isFeatureSplit = attrs.getAttributeBooleanValue(i, false); - break; - case "isSplitRequired": - isSplitRequired = attrs.getAttributeBooleanValue(i, false); - break; - } - } - // Only search the tree when the tag is the direct child of tag int type; final int searchDepth = parser.getDepth() + 1; @@ -427,34 +399,23 @@ public class ApkLiteParseUtils { } if (ParsingPackageUtils.TAG_PACKAGE_VERIFIER.equals(parser.getName())) { - final VerifierInfo verifier = parseVerifier(attrs); + final VerifierInfo verifier = parseVerifier(parser); if (verifier != null) { verifiers.add(verifier); } } else if (ParsingPackageUtils.TAG_APPLICATION.equals(parser.getName())) { - for (int i = 0; i < attrs.getAttributeCount(); ++i) { - final String attr = attrs.getAttributeName(i); - switch (attr) { - case "debuggable": - debuggable = attrs.getAttributeBooleanValue(i, false); - break; - case "multiArch": - multiArch = attrs.getAttributeBooleanValue(i, false); - break; - case "use32bitAbi": - use32bitAbi = attrs.getAttributeBooleanValue(i, false); - break; - case "extractNativeLibs": - extractNativeLibs = attrs.getAttributeBooleanValue(i, true); - break; - case "useEmbeddedDex": - useEmbeddedDex = attrs.getAttributeBooleanValue(i, false); - break; - case "rollbackDataPolicy": - rollbackDataPolicy = attrs.getAttributeIntValue(i, 0); - break; - } - } + debuggable = parser.getAttributeBooleanValue(ANDROID_RES_NAMESPACE, "debuggable", + false); + multiArch = parser.getAttributeBooleanValue(ANDROID_RES_NAMESPACE, "multiArch", + false); + use32bitAbi = parser.getAttributeBooleanValue(ANDROID_RES_NAMESPACE, "use32bitAbi", + false); + extractNativeLibs = parser.getAttributeBooleanValue(ANDROID_RES_NAMESPACE, + "extractNativeLibs", true); + useEmbeddedDex = parser.getAttributeBooleanValue(ANDROID_RES_NAMESPACE, + "useEmbeddedDex", false); + rollbackDataPolicy = parser.getAttributeIntValue(ANDROID_RES_NAMESPACE, + "rollbackDataPolicy", 0); final int innerDepth = parser.getDepth(); int innerType; @@ -470,52 +431,79 @@ public class ApkLiteParseUtils { } if (ParsingPackageUtils.TAG_PROFILEABLE.equals(parser.getName())) { - for (int i = 0; i < attrs.getAttributeCount(); ++i) { - final String attr = attrs.getAttributeName(i); - if ("shell".equals(attr)) { - profilableByShell = attrs.getAttributeBooleanValue(i, - profilableByShell); - } - } + profilableByShell = parser.getAttributeBooleanValue(ANDROID_RES_NAMESPACE, + "shell", profilableByShell); } } } else if (ParsingPackageUtils.TAG_OVERLAY.equals(parser.getName())) { - for (int i = 0; i < attrs.getAttributeCount(); ++i) { - final String attr = attrs.getAttributeName(i); - if ("requiredSystemPropertyName".equals(attr)) { - requiredSystemPropertyName = attrs.getAttributeValue(i); - } else if ("requiredSystemPropertyValue".equals(attr)) { - requiredSystemPropertyValue = attrs.getAttributeValue(i); - } else if ("targetPackage".equals(attr)) { - targetPackage = attrs.getAttributeValue(i);; - } else if ("isStatic".equals(attr)) { - overlayIsStatic = attrs.getAttributeBooleanValue(i, false); - } else if ("priority".equals(attr)) { - overlayPriority = attrs.getAttributeIntValue(i, 0); - } - } + requiredSystemPropertyName = parser.getAttributeValue(ANDROID_RES_NAMESPACE, + "requiredSystemPropertyName"); + requiredSystemPropertyValue = parser.getAttributeValue(ANDROID_RES_NAMESPACE, + "requiredSystemPropertyValue"); + targetPackage = parser.getAttributeValue(ANDROID_RES_NAMESPACE, "targetPackage"); + overlayIsStatic = parser.getAttributeBooleanValue(ANDROID_RES_NAMESPACE, "isStatic", + false); + overlayPriority = parser.getAttributeIntValue(ANDROID_RES_NAMESPACE, "priority", 0); } else if (ParsingPackageUtils.TAG_USES_SPLIT.equals(parser.getName())) { if (usesSplitName != null) { Slog.w(TAG, "Only one permitted. Ignoring others."); continue; } - usesSplitName = attrs.getAttributeValue(PackageParser.ANDROID_RESOURCES, "name"); + usesSplitName = parser.getAttributeValue(ANDROID_RES_NAMESPACE, "name"); if (usesSplitName == null) { return input.error(PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, " tag requires 'android:name' attribute"); } } else if (ParsingPackageUtils.TAG_USES_SDK.equals(parser.getName())) { - for (int i = 0; i < attrs.getAttributeCount(); ++i) { - final String attr = attrs.getAttributeName(i); - if ("targetSdkVersion".equals(attr)) { - targetSdkVersion = attrs.getAttributeIntValue(i, - DEFAULT_TARGET_SDK_VERSION); - } - if ("minSdkVersion".equals(attr)) { - minSdkVersion = attrs.getAttributeIntValue(i, DEFAULT_MIN_SDK_VERSION); + // Mirrors ParsingPackageUtils#parseUsesSdk until lite and full parsing is combined + String minSdkVersionString = parser.getAttributeValue(ANDROID_RES_NAMESPACE, + "minSdkVersion"); + String targetSdkVersionString = parser.getAttributeValue(ANDROID_RES_NAMESPACE, + "targetSdkVersion"); + + int minVer = DEFAULT_MIN_SDK_VERSION; + String minCode = null; + int targetVer = DEFAULT_TARGET_SDK_VERSION; + String targetCode = null; + + if (!TextUtils.isEmpty(minSdkVersionString)) { + try { + minVer = Integer.parseInt(minSdkVersionString); + } catch (NumberFormatException ignored) { + minCode = minSdkVersionString; } } + + if (!TextUtils.isEmpty(targetSdkVersionString)) { + try { + targetVer = Integer.parseInt(targetSdkVersionString); + } catch (NumberFormatException ignored) { + targetCode = targetSdkVersionString; + if (minCode == null) { + minCode = targetCode; + } + } + } else { + targetVer = minVer; + targetCode = minCode; + } + + ParseResult targetResult = ParsingPackageUtils.computeTargetSdkVersion( + targetVer, targetCode, ParsingPackageUtils.SDK_CODENAMES, input); + if (targetResult.isError()) { + return input.error(targetResult); + } + + ParseResult minResult = ParsingPackageUtils.computeMinSdkVersion( + minVer, minCode, ParsingPackageUtils.SDK_VERSION, + ParsingPackageUtils.SDK_CODENAMES, input); + if (minResult.isError()) { + return input.error(minResult); + } + + targetSdkVersion = targetResult.getResult(); + minSdkVersion = minResult.getResult(); } } @@ -541,7 +529,7 @@ public class ApkLiteParseUtils { } public static ParseResult> parsePackageSplitNames(ParseInput input, - XmlPullParser parser, AttributeSet attrs) throws IOException, XmlPullParserException { + XmlResourceParser parser) throws IOException, XmlPullParserException { int type; while ((type = parser.next()) != XmlPullParser.START_TAG && type != XmlPullParser.END_DOCUMENT) { @@ -556,7 +544,7 @@ public class ApkLiteParseUtils { "No tag"); } - final String packageName = attrs.getAttributeValue(null, "package"); + final String packageName = parser.getAttributeValue(null, "package"); if (!"android".equals(packageName)) { final ParseResult nameResult = validateName(input, packageName, true, true); if (nameResult.isError()) { @@ -565,7 +553,7 @@ public class ApkLiteParseUtils { } } - String splitName = attrs.getAttributeValue(null, "split"); + String splitName = parser.getAttributeValue(null, "split"); if (splitName != null) { if (splitName.length() == 0) { splitName = null; @@ -583,22 +571,8 @@ public class ApkLiteParseUtils { } public static VerifierInfo parseVerifier(AttributeSet attrs) { - String packageName = null; - String encodedPublicKey = null; - - final int attrCount = attrs.getAttributeCount(); - for (int i = 0; i < attrCount; i++) { - final int attrResId = attrs.getAttributeNameResource(i); - switch (attrResId) { - case R.attr.name: - packageName = attrs.getAttributeValue(i); - break; - - case R.attr.publicKey: - encodedPublicKey = attrs.getAttributeValue(i); - break; - } - } + String packageName = attrs.getAttributeValue(ANDROID_RES_NAMESPACE, "name"); + String encodedPublicKey = attrs.getAttributeValue(ANDROID_RES_NAMESPACE, "publicKey"); if (packageName == null || packageName.length() == 0) { Slog.i(TAG, "verifier package name was null; skipping"); diff --git a/core/java/android/content/pm/parsing/ParsingPackageImpl.java b/core/java/android/content/pm/parsing/ParsingPackageImpl.java index b0342aa95fc99..c318a796d859a 100644 --- a/core/java/android/content/pm/parsing/ParsingPackageImpl.java +++ b/core/java/android/content/pm/parsing/ParsingPackageImpl.java @@ -356,7 +356,7 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { private float minAspectRatio; @Nullable private SparseIntArray minExtensionVersions; - private int minSdkVersion; + private int minSdkVersion = ParsingUtils.DEFAULT_MIN_SDK_VERSION; private int networkSecurityConfigRes; @Nullable private CharSequence nonLocalizedLabel; @@ -369,7 +369,7 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { private int requiresSmallestWidthDp; private int roundIconRes; private int targetSandboxVersion; - private int targetSdkVersion; + private int targetSdkVersion = ParsingUtils.DEFAULT_TARGET_SDK_VERSION; @Nullable @DataClass.ParcelWith(ForInternedString.class) private String taskAffinity; diff --git a/core/java/android/content/pm/parsing/ParsingPackageUtils.java b/core/java/android/content/pm/parsing/ParsingPackageUtils.java index 5d74e7452a0b7..9410d9a11ff82 100644 --- a/core/java/android/content/pm/parsing/ParsingPackageUtils.java +++ b/core/java/android/content/pm/parsing/ParsingPackageUtils.java @@ -582,12 +582,12 @@ public class ParsingPackageUtils { */ private ParseResult parseBaseApk(ParseInput input, String apkPath, String codePath, Resources res, XmlResourceParser parser, int flags) - throws XmlPullParserException, IOException, PackageParserException { + throws XmlPullParserException, IOException { final String splitName; final String pkgName; ParseResult> packageSplitResult = - ApkLiteParseUtils.parsePackageSplitNames(input, parser, parser); + ApkLiteParseUtils.parsePackageSplitNames(input, parser); if (packageSplitResult.isError()) { return input.error(packageSplitResult); } @@ -1460,9 +1460,9 @@ public class ParsingPackageUtils { if (SDK_VERSION > 0) { TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestUsesSdk); try { - int minVers = 1; + int minVers = ParsingUtils.DEFAULT_MIN_SDK_VERSION; String minCode = null; - int targetVers = 0; + int targetVers = ParsingUtils.DEFAULT_TARGET_SDK_VERSION; String targetCode = null; TypedValue val = sa.peekValue(R.styleable.AndroidManifestUsesSdk_minSdkVersion); diff --git a/core/java/android/content/pm/parsing/ParsingUtils.java b/core/java/android/content/pm/parsing/ParsingUtils.java index 5da5fbf4d8a7b..07ec6a80c2832 100644 --- a/core/java/android/content/pm/parsing/ParsingUtils.java +++ b/core/java/android/content/pm/parsing/ParsingUtils.java @@ -35,6 +35,11 @@ public class ParsingUtils { public static final String TAG = "PackageParsing"; + 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_TARGET_SDK_VERSION = 0; + @Nullable public static String buildClassName(String pkg, CharSequence clsSeq) { if (clsSeq == null || clsSeq.length() <= 0) {