|
|
|
|
@@ -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<ApkLite> parseApkLite(ParseInput input, String codePath,
|
|
|
|
|
XmlPullParser parser, AttributeSet attrs, PackageParser.SigningDetails signingDetails)
|
|
|
|
|
XmlResourceParser parser, PackageParser.SigningDetails signingDetails)
|
|
|
|
|
throws IOException, XmlPullParserException {
|
|
|
|
|
ParseResult<Pair<String, String>> result = parsePackageSplitNames(input, parser, attrs);
|
|
|
|
|
ParseResult<Pair<String, String>> result = parsePackageSplitNames(input, parser);
|
|
|
|
|
if (result.isError()) {
|
|
|
|
|
return input.error(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Pair<String, String> 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 <manifest> 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 <uses-split> 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,
|
|
|
|
|
"<uses-split> 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<Integer> targetResult = ParsingPackageUtils.computeTargetSdkVersion(
|
|
|
|
|
targetVer, targetCode, ParsingPackageUtils.SDK_CODENAMES, input);
|
|
|
|
|
if (targetResult.isError()) {
|
|
|
|
|
return input.error(targetResult);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ParseResult<Integer> 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<Pair<String, String>> 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 <manifest> 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");
|
|
|
|
|
|