summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTreeHugger Robot <treehugger-gerrit@google.com>2020-05-06 04:11:34 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2020-05-06 04:11:34 +0000
commit30de689af98bbaf2120690d1bff4e4804a621bdb (patch)
tree3e06e51a89380c7024643df500d2240255f1d47a
parent13c64e59ae5de10512e1cf2f6d3aba176130321c (diff)
parenta83fad74b45e702b5fcf8cbf1b0b0bf6786bd2df (diff)
Merge "Migrate remaining parsePackage V1 to V2" into rvc-dev am: a83fad74b4
Change-Id: Ic2c575360d3356c21b54bdeebbc66ab0b4bd6d64
-rw-r--r--core/java/android/content/pm/PackageManager.java39
-rw-r--r--core/java/android/content/pm/PackageParser.java4
-rw-r--r--core/java/android/content/pm/parsing/ApkLiteParseUtils.java222
-rw-r--r--core/java/android/content/pm/parsing/ParsingPackageUtils.java159
-rw-r--r--core/java/android/content/pm/parsing/result/ParseTypeImpl.java26
-rw-r--r--core/tests/coretests/src/android/content/pm/PackageManagerTests.java157
-rw-r--r--packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java10
-rw-r--r--packages/PackageInstaller/src/com/android/packageinstaller/PackageUtil.java13
-rw-r--r--packages/PackageInstaller/src/com/android/packageinstaller/wear/WearPackageInstallerService.java56
-rw-r--r--services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java2
-rw-r--r--services/core/java/com/android/server/pm/ApexManager.java2
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerSession.java39
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java28
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerShellCommand.java19
-rw-r--r--services/core/java/com/android/server/pm/parsing/PackageParser2.java16
-rw-r--r--services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java15
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java13
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/dex/DexMetadataHelperTest.java14
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt24
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java17
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/parsing/PackageParsingDeferErrorTest.kt17
21 files changed, 525 insertions, 367 deletions
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index d06a69caf837..4d718ef6bebe 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -47,8 +47,11 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentSender;
-import android.content.pm.PackageParser.PackageParserException;
import android.content.pm.dex.ArtManager;
+import android.content.pm.parsing.PackageInfoWithoutStateUtils;
+import android.content.pm.parsing.ParsingPackage;
+import android.content.pm.parsing.ParsingPackageUtils;
+import android.content.pm.parsing.result.ParseResult;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
import android.graphics.Rect;
@@ -6037,28 +6040,24 @@ public abstract class PackageManager {
@Nullable
public PackageInfo getPackageArchiveInfo(@NonNull String archiveFilePath,
@PackageInfoFlags int flags) {
- final PackageParser parser = new PackageParser();
- parser.setCallback(new PackageParser.CallbackImpl(this));
- final File apkFile = new File(archiveFilePath);
- try {
- if ((flags & (MATCH_DIRECT_BOOT_UNAWARE | MATCH_DIRECT_BOOT_AWARE)) != 0) {
- // Caller expressed an explicit opinion about what encryption
- // aware/unaware components they want to see, so fall through and
- // give them what they want
- } else {
- // Caller expressed no opinion, so match everything
- flags |= MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE;
- }
+ if ((flags & (PackageManager.MATCH_DIRECT_BOOT_UNAWARE
+ | PackageManager.MATCH_DIRECT_BOOT_AWARE)) == 0) {
+ // Caller expressed no opinion about what encryption
+ // aware/unaware components they want to see, so match both
+ flags |= PackageManager.MATCH_DIRECT_BOOT_AWARE
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
+ }
- PackageParser.Package pkg = parser.parseMonolithicPackage(apkFile, 0);
- if ((flags & GET_SIGNATURES) != 0) {
- PackageParser.collectCertificates(pkg, false /* skipVerify */);
- }
- PackageUserState state = new PackageUserState();
- return PackageParser.generatePackageInfo(pkg, null, flags, 0, 0, null, state);
- } catch (PackageParserException e) {
+ boolean collectCertificates = (flags & PackageManager.GET_SIGNATURES) != 0
+ || (flags & PackageManager.GET_SIGNING_CERTIFICATES) != 0;
+
+ ParseResult<ParsingPackage> result = ParsingPackageUtils.parseDefaultOneTime(
+ new File(archiveFilePath), 0, collectCertificates);
+ if (result.isError()) {
return null;
}
+ return PackageInfoWithoutStateUtils.generate(result.getResult(), null, flags, 0, 0, null,
+ new PackageUserState(), UserHandle.getCallingUserId());
}
/**
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 3b3521f834aa..312e98e77636 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -1517,6 +1517,10 @@ public class PackageParser {
? null : "must have at least one '.' separator";
}
+ /**
+ * @deprecated Use {@link android.content.pm.parsing.ApkLiteParseUtils#parsePackageSplitNames}
+ */
+ @Deprecated
public static Pair<String, String> parsePackageSplitNames(XmlPullParser parser,
AttributeSet attrs) throws IOException, XmlPullParserException,
PackageParserException {
diff --git a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
index 2f416a2538ba..d2172d3741d1 100644
--- a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
+++ b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
@@ -16,6 +16,8 @@
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.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
import android.compat.annotation.UnsupportedAppUsage;
@@ -23,6 +25,8 @@ import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageParser;
import android.content.pm.VerifierInfo;
+import android.content.pm.parsing.result.ParseInput;
+import android.content.pm.parsing.result.ParseResult;
import android.content.res.ApkAssets;
import android.content.res.XmlResourceParser;
import android.os.Trace;
@@ -70,82 +74,93 @@ public class ApkLiteParseUtils {
*
* @see PackageParser#parsePackage(File, int)
*/
- @UnsupportedAppUsage
- public static PackageParser.PackageLite parsePackageLite(File packageFile, int flags)
- throws PackageParser.PackageParserException {
+ public static ParseResult<PackageParser.PackageLite> parsePackageLite(ParseInput input,
+ File packageFile, int flags) {
if (packageFile.isDirectory()) {
- return parseClusterPackageLite(packageFile, flags);
+ return parseClusterPackageLite(input, packageFile, flags);
} else {
- return parseMonolithicPackageLite(packageFile, flags);
+ return parseMonolithicPackageLite(input, packageFile, flags);
}
}
- public static PackageParser.PackageLite parseMonolithicPackageLite(File packageFile, int flags)
- throws PackageParser.PackageParserException {
+ public static ParseResult<PackageParser.PackageLite> parseMonolithicPackageLite(
+ ParseInput input, File packageFile, int flags) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parseApkLite");
- final PackageParser.ApkLite baseApk = parseApkLite(packageFile, flags);
- final String packagePath = packageFile.getAbsolutePath();
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
- return new PackageParser.PackageLite(packagePath, baseApk, null, null, null, null,
- null, null);
+ try {
+ ParseResult<PackageParser.ApkLite> result = parseApkLite(input, packageFile, flags);
+ if (result.isError()) {
+ return input.error(result);
+ }
+
+ final PackageParser.ApkLite baseApk = result.getResult();
+ final String packagePath = packageFile.getAbsolutePath();
+ return input.success(
+ new PackageParser.PackageLite(packagePath, baseApk, null, null, null, null,
+ null, null));
+ } finally {
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ }
}
- public static PackageParser.PackageLite parseClusterPackageLite(File packageDir, int flags)
- throws PackageParser.PackageParserException {
+ public static ParseResult<PackageParser.PackageLite> parseClusterPackageLite(ParseInput input,
+ File packageDir, int flags) {
final File[] files = packageDir.listFiles();
if (ArrayUtils.isEmpty(files)) {
- throw new PackageParser.PackageParserException(
- PackageManager.INSTALL_PARSE_FAILED_NOT_APK, "No packages found in split");
+ return input.error(PackageManager.INSTALL_PARSE_FAILED_NOT_APK,
+ "No packages found in split");
}
// Apk directory is directly nested under the current directory
if (files.length == 1 && files[0].isDirectory()) {
- return parseClusterPackageLite(files[0], flags);
+ return parseClusterPackageLite(input, files[0], flags);
}
String packageName = null;
int versionCode = 0;
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parseApkLite");
final ArrayMap<String, PackageParser.ApkLite> apks = new ArrayMap<>();
- for (File file : files) {
- if (PackageParser.isApkFile(file)) {
- final PackageParser.ApkLite lite = parseApkLite(file, flags);
-
- // Assert that all package names and version codes are
- // consistent with the first one we encounter.
- if (packageName == null) {
- packageName = lite.packageName;
- versionCode = lite.versionCode;
- } else {
- if (!packageName.equals(lite.packageName)) {
- throw new PackageParser.PackageParserException(
- PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST,
- "Inconsistent package " + lite.packageName + " in " + file
- + "; expected " + packageName);
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parseApkLite");
+ try {
+ for (File file : files) {
+ if (PackageParser.isApkFile(file)) {
+ ParseResult<PackageParser.ApkLite> result = parseApkLite(input, file, flags);
+ if (result.isError()) {
+ return input.error(result);
}
- if (versionCode != lite.versionCode) {
- throw new PackageParser.PackageParserException(
- PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST,
- "Inconsistent version " + lite.versionCode + " in " + file
- + "; expected " + versionCode);
+
+ final PackageParser.ApkLite lite = result.getResult();
+ // Assert that all package names and version codes are
+ // consistent with the first one we encounter.
+ if (packageName == null) {
+ packageName = lite.packageName;
+ versionCode = lite.versionCode;
+ } else {
+ if (!packageName.equals(lite.packageName)) {
+ return input.error(PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST,
+ "Inconsistent package " + lite.packageName + " in " + file
+ + "; expected " + packageName);
+ }
+ if (versionCode != lite.versionCode) {
+ return input.error(PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST,
+ "Inconsistent version " + lite.versionCode + " in " + file
+ + "; expected " + versionCode);
+ }
}
- }
- // Assert that each split is defined only oncuses-static-libe
- if (apks.put(lite.splitName, lite) != null) {
- throw new PackageParser.PackageParserException(
- PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST,
- "Split name " + lite.splitName
- + " defined more than once; most recent was " + file);
+ // Assert that each split is defined only oncuses-static-libe
+ if (apks.put(lite.splitName, lite) != null) {
+ return input.error(PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST,
+ "Split name " + lite.splitName
+ + " defined more than once; most recent was " + file);
+ }
}
}
+ } finally {
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
final PackageParser.ApkLite baseApk = apks.remove(null);
if (baseApk == null) {
- throw new PackageParser.PackageParserException(
- PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST,
+ return input.error(PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST,
"Missing base APK in " + packageDir);
}
@@ -180,8 +195,9 @@ public class ApkLiteParseUtils {
}
final String codePath = packageDir.getAbsolutePath();
- return new PackageParser.PackageLite(codePath, baseApk, splitNames, isFeatureSplits,
- usesSplitNames, configForSplits, splitCodePaths, splitRevisionCodes);
+ return input.success(new PackageParser.PackageLite(codePath, baseApk, splitNames,
+ isFeatureSplits, usesSplitNames, configForSplits, splitCodePaths,
+ splitRevisionCodes));
}
/**
@@ -192,9 +208,9 @@ public class ApkLiteParseUtils {
* @param flags optional parse flags, such as
* {@link PackageParser#PARSE_COLLECT_CERTIFICATES}
*/
- public static PackageParser.ApkLite parseApkLite(File apkFile, int flags)
- throws PackageParser.PackageParserException {
- return parseApkLiteInner(apkFile, null, null, flags);
+ public static ParseResult<PackageParser.ApkLite> parseApkLite(ParseInput input, File apkFile,
+ int flags) {
+ return parseApkLiteInner(input, apkFile, null, null, flags);
}
/**
@@ -206,13 +222,13 @@ public class ApkLiteParseUtils {
* @param flags optional parse flags, such as
* {@link PackageParser#PARSE_COLLECT_CERTIFICATES}
*/
- public static PackageParser.ApkLite parseApkLite(FileDescriptor fd, String debugPathName,
- int flags) throws PackageParser.PackageParserException {
- return parseApkLiteInner(null, fd, debugPathName, flags);
+ public static ParseResult<PackageParser.ApkLite> parseApkLite(ParseInput input,
+ FileDescriptor fd, String debugPathName, int flags) {
+ return parseApkLiteInner(input, null, fd, debugPathName, flags);
}
- private static PackageParser.ApkLite parseApkLiteInner(File apkFile, FileDescriptor fd,
- String debugPathName, int flags) throws PackageParser.PackageParserException {
+ private static ParseResult<PackageParser.ApkLite> parseApkLiteInner(ParseInput input,
+ File apkFile, FileDescriptor fd, String debugPathName, int flags) {
final String apkPath = fd != null ? debugPathName : apkFile.getAbsolutePath();
XmlResourceParser parser = null;
@@ -223,8 +239,7 @@ public class ApkLiteParseUtils {
? ApkAssets.loadFromFd(fd, debugPathName, 0 /* flags */, null /* assets */)
: ApkAssets.loadFromPath(apkPath);
} catch (IOException e) {
- throw new PackageParser.PackageParserException(
- PackageManager.INSTALL_PARSE_FAILED_NOT_APK,
+ return input.error(PackageManager.INSTALL_PARSE_FAILED_NOT_APK,
"Failed to parse " + apkPath, e);
}
@@ -235,9 +250,15 @@ public class ApkLiteParseUtils {
final boolean skipVerify = (flags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0;
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates");
try {
- signingDetails = ParsingPackageUtils.collectCertificates(apkFile.getAbsolutePath(),
- skipVerify, false, PackageParser.SigningDetails.UNKNOWN,
- DEFAULT_TARGET_SDK_VERSION);
+ ParseResult<PackageParser.SigningDetails> result =
+ ParsingPackageUtils.getSigningDetails(input,
+ apkFile.getAbsolutePath(), skipVerify, false,
+ PackageParser.SigningDetails.UNKNOWN,
+ DEFAULT_TARGET_SDK_VERSION);
+ if (result.isError()) {
+ return input.error(result);
+ }
+ signingDetails = result.getResult();
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
@@ -246,12 +267,10 @@ public class ApkLiteParseUtils {
}
final AttributeSet attrs = parser;
- return parseApkLite(apkPath, parser, attrs, signingDetails);
-
+ return parseApkLite(input, apkPath, parser, attrs, signingDetails);
} catch (XmlPullParserException | IOException | RuntimeException e) {
Slog.w(TAG, "Failed to parse " + apkPath, e);
- throw new PackageParser.PackageParserException(
- PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
+ return input.error(PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
"Failed to parse " + apkPath, e);
} finally {
IoUtils.closeQuietly(parser);
@@ -265,12 +284,16 @@ public class ApkLiteParseUtils {
}
}
- private static PackageParser.ApkLite parseApkLite(
+ private static ParseResult<PackageParser.ApkLite> parseApkLite(ParseInput input,
String codePath, XmlPullParser parser, AttributeSet attrs,
PackageParser.SigningDetails signingDetails)
- throws IOException, XmlPullParserException, PackageParser.PackageParserException {
- final Pair<String, String> packageSplit = PackageParser.parsePackageSplitNames(
- parser, attrs);
+ throws IOException, XmlPullParserException {
+ ParseResult<Pair<String, String>> result = parsePackageSplitNames(input, parser, attrs);
+ if (result.isError()) {
+ return input.error(result);
+ }
+
+ Pair<String, String> packageSplit = result.getResult();
int installLocation = PARSE_DEFAULT_INSTALL_LOCATION;
int versionCode = 0;
@@ -394,8 +417,7 @@ public class ApkLiteParseUtils {
usesSplitName = attrs.getAttributeValue(PackageParser.ANDROID_RESOURCES, "name");
if (usesSplitName == null) {
- throw new PackageParser.PackageParserException(
- PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ return input.error(PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
"<uses-split> tag requires 'android:name' attribute");
}
} else if (PackageParser.TAG_USES_SDK.equals(parser.getName())) {
@@ -423,12 +445,54 @@ public class ApkLiteParseUtils {
overlayPriority = 0;
}
- return new PackageParser.ApkLite(codePath, packageSplit.first, packageSplit.second,
- isFeatureSplit, configForSplit, usesSplitName, isSplitRequired, versionCode,
- versionCodeMajor, revisionCode, installLocation, verifiers, signingDetails,
- coreApp, debuggable, multiArch, use32bitAbi, useEmbeddedDex, extractNativeLibs,
- isolatedSplits, targetPackage, overlayIsStatic, overlayPriority, minSdkVersion,
- targetSdkVersion);
+ return input.success(new PackageParser.ApkLite(codePath, packageSplit.first,
+ packageSplit.second, isFeatureSplit, configForSplit, usesSplitName, isSplitRequired,
+ versionCode, versionCodeMajor, revisionCode, installLocation, verifiers,
+ signingDetails, coreApp, debuggable, multiArch, use32bitAbi, useEmbeddedDex,
+ extractNativeLibs, isolatedSplits, targetPackage, overlayIsStatic, overlayPriority,
+ minSdkVersion, targetSdkVersion));
+ }
+
+ public static ParseResult<Pair<String, String>> parsePackageSplitNames(ParseInput input,
+ XmlPullParser parser, AttributeSet attrs) throws IOException, XmlPullParserException {
+ int type;
+ while ((type = parser.next()) != XmlPullParser.START_TAG
+ && type != XmlPullParser.END_DOCUMENT) {
+ }
+
+ if (type != XmlPullParser.START_TAG) {
+ return input.error(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ "No start tag found");
+ }
+ if (!parser.getName().equals(PackageParser.TAG_MANIFEST)) {
+ return input.error(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ "No <manifest> tag");
+ }
+
+ final String packageName = attrs.getAttributeValue(null, "package");
+ if (!"android".equals(packageName)) {
+ final String error = PackageParser.validateName(packageName, true, true);
+ if (error != null) {
+ return input.error(INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
+ "Invalid manifest package: " + error);
+ }
+ }
+
+ String splitName = attrs.getAttributeValue(null, "split");
+ if (splitName != null) {
+ if (splitName.length() == 0) {
+ splitName = null;
+ } else {
+ final String error = PackageParser.validateName(splitName, false, false);
+ if (error != null) {
+ return input.error(INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
+ "Invalid manifest split: " + error);
+ }
+ }
+ }
+
+ return input.success(Pair.create(packageName.intern(),
+ (splitName != null) ? splitName.intern() : splitName));
}
public static VerifierInfo parseVerifier(AttributeSet attrs) {
diff --git a/core/java/android/content/pm/parsing/ParsingPackageUtils.java b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
index d3d15c82dd1b..9372c957af34 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageUtils.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
@@ -29,6 +29,7 @@ import static android.os.Build.VERSION_CODES.O;
import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
import android.annotation.AnyRes;
+import android.annotation.CheckResult;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -135,23 +136,32 @@ public class ParsingPackageUtils {
* for feature support.
*/
@NonNull
- public static ParseResult<ParsingPackage> parseDefaultOneTime(File file, int flags,
- @NonNull ParseInput.Callback inputCallback, @NonNull Callback callback) {
- if ((flags & (PackageManager.MATCH_DIRECT_BOOT_UNAWARE
- | PackageManager.MATCH_DIRECT_BOOT_AWARE)) == 0) {
- // Caller expressed no opinion about what encryption
- // aware/unaware components they want to see, so match both
- flags |= PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
- }
-
- ParseInput input = new ParseTypeImpl(inputCallback).reset();
+ public static ParseResult<ParsingPackage> parseDefaultOneTime(File file,
+ @PackageParser.ParseFlags int parseFlags, boolean collectCertificates) {
+ ParseInput input = ParseTypeImpl.forDefaultParsing().reset();
ParseResult<ParsingPackage> result;
-
- ParsingPackageUtils parser = new ParsingPackageUtils(false, null, null, callback);
+ ParsingPackageUtils parser = new ParsingPackageUtils(false, null, null, new Callback() {
+ @Override
+ public boolean hasFeature(String feature) {
+ // Assume the device doesn't support anything. This will affect permission parsing
+ // and will force <uses-permission/> declarations to include all requiredNotFeature
+ // permissions and exclude all requiredFeature permissions. This mirrors the old
+ // behavior.
+ return false;
+ }
+
+ @Override
+ public ParsingPackage startParsingPackage(
+ @NonNull String packageName,
+ @NonNull String baseCodePath,
+ @NonNull String codePath,
+ @NonNull TypedArray manifestArray, boolean isCoreApp) {
+ return new ParsingPackageImpl(packageName, baseCodePath, codePath, manifestArray);
+ }
+ });
try {
- result = parser.parsePackage(input, file, flags);
+ result = parser.parsePackage(input, file, parseFlags);
if (result.isError()) {
return result;
}
@@ -162,9 +172,9 @@ public class ParsingPackageUtils {
try {
ParsingPackage pkg = result.getResult();
- if ((flags & PackageManager.GET_SIGNATURES) != 0
- || (flags & PackageManager.GET_SIGNING_CERTIFICATES) != 0) {
- ParsingPackageUtils.collectCertificates(pkg, false /* skipVerify */);
+ if (collectCertificates) {
+ pkg.setSigningDetails(
+ ParsingPackageUtils.getSigningDetails(pkg, false /* skipVerify */));
}
return input.success(pkg);
@@ -197,7 +207,7 @@ public class ParsingPackageUtils {
* and unique split names.
* <p>
* Note that this <em>does not</em> perform signature verification; that
- * must be done separately in {@link #collectCertificates(ParsingPackageRead, boolean)}.
+ * must be done separately in {@link #getSigningDetails(ParsingPackageRead, boolean)}.
*
* If {@code useCaches} is true, the package parser might return a cached
* result from a previous parse of the same {@code packageFile} with the same
@@ -223,12 +233,17 @@ public class ParsingPackageUtils {
* split names.
* <p>
* Note that this <em>does not</em> perform signature verification; that
- * must be done separately in {@link #collectCertificates(ParsingPackageRead, boolean)}.
+ * must be done separately in {@link #getSigningDetails(ParsingPackageRead, boolean)}.
*/
private ParseResult<ParsingPackage> parseClusterPackage(ParseInput input, File packageDir,
- int flags) throws PackageParserException {
- final PackageParser.PackageLite lite = ApkLiteParseUtils.parseClusterPackageLite(packageDir,
- 0);
+ int flags) {
+ ParseResult<PackageParser.PackageLite> liteResult =
+ ApkLiteParseUtils.parseClusterPackageLite(input, packageDir, 0);
+ if (liteResult.isError()) {
+ return input.error(liteResult);
+ }
+
+ final PackageParser.PackageLite lite = liteResult.getResult();
if (mOnlyCoreApps && !lite.coreApp) {
return input.error(INSTALL_PARSE_FAILED_ONLY_COREAPP_ALLOWED,
"Not a coreApp: " + packageDir);
@@ -275,6 +290,9 @@ public class ParsingPackageUtils {
pkg.setUse32BitAbi(lite.use32bitAbi);
return input.success(pkg);
+ } catch (PackageParserException e) {
+ return input.error(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
+ "Failed to load assets: " + lite.baseCodePath, e);
} finally {
IoUtils.closeQuietly(assetLoader);
}
@@ -284,12 +302,17 @@ public class ParsingPackageUtils {
* Parse the given APK file, treating it as as a single monolithic package.
* <p>
* Note that this <em>does not</em> perform signature verification; that
- * must be done separately in {@link #collectCertificates(ParsingPackageRead, boolean)}.
+ * must be done separately in {@link #getSigningDetails(ParsingPackageRead, boolean)}.
*/
private ParseResult<ParsingPackage> parseMonolithicPackage(ParseInput input, File apkFile,
int flags) throws PackageParserException {
- final PackageParser.PackageLite lite = ApkLiteParseUtils.parseMonolithicPackageLite(apkFile,
- flags);
+ ParseResult<PackageParser.PackageLite> liteResult =
+ ApkLiteParseUtils.parseMonolithicPackageLite(input, apkFile, flags);
+ if (liteResult.isError()) {
+ return input.error(liteResult);
+ }
+
+ final PackageParser.PackageLite lite = liteResult.getResult();
if (mOnlyCoreApps && !lite.coreApp) {
return input.error(INSTALL_PARSE_FAILED_ONLY_COREAPP_ALLOWED,
"Not a coreApp: " + apkFile);
@@ -430,20 +453,21 @@ public class ParsingPackageUtils {
final String splitName;
final String pkgName;
- try {
- Pair<String, String> packageSplit = PackageParser.parsePackageSplitNames(parser,
- parser);
- pkgName = packageSplit.first;
- splitName = packageSplit.second;
+ ParseResult<Pair<String, String>> packageSplitResult =
+ ApkLiteParseUtils.parsePackageSplitNames(input, parser, parser);
+ if (packageSplitResult.isError()) {
+ return input.error(packageSplitResult);
+ }
- if (!TextUtils.isEmpty(splitName)) {
- return input.error(
- PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
- "Expected base APK, but found split " + splitName
- );
- }
- } catch (PackageParserException e) {
- return input.error(PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME);
+ Pair<String, String> packageSplit = packageSplitResult.getResult();
+ pkgName = packageSplit.first;
+ splitName = packageSplit.second;
+
+ if (!TextUtils.isEmpty(splitName)) {
+ return input.error(
+ PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
+ "Expected base APK, but found split " + splitName
+ );
}
final TypedArray manifestArray = res.obtainAttributes(parser, R.styleable.AndroidManifest);
@@ -2624,31 +2648,53 @@ public class ParsingPackageUtils {
/**
* Collect certificates from all the APKs described in the given package. Also asserts that
* all APK contents are signed correctly and consistently.
+ *
+ * TODO(b/155513789): Remove this in favor of collecting certificates during the original parse
+ * call if requested. Leaving this as an optional method for the caller means we have to
+ * construct a dummy ParseInput.
*/
- public static SigningDetails collectCertificates(ParsingPackageRead pkg, boolean skipVerify)
+ @CheckResult
+ public static SigningDetails getSigningDetails(ParsingPackageRead pkg, boolean skipVerify)
throws PackageParserException {
SigningDetails signingDetails = SigningDetails.UNKNOWN;
+ ParseInput input = ParseTypeImpl.forDefaultParsing().reset();
+
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates");
try {
- signingDetails = collectCertificates(
+ ParseResult<SigningDetails> result = getSigningDetails(
+ input,
pkg.getBaseCodePath(),
skipVerify,
pkg.isStaticSharedLibrary(),
signingDetails,
pkg.getTargetSdkVersion()
);
+ if (result.isError()) {
+ throw new PackageParser.PackageParserException(result.getErrorCode(),
+ result.getErrorMessage(), result.getException());
+ }
+
+ signingDetails = result.getResult();
String[] splitCodePaths = pkg.getSplitCodePaths();
if (!ArrayUtils.isEmpty(splitCodePaths)) {
for (int i = 0; i < splitCodePaths.length; i++) {
- signingDetails = collectCertificates(
+ result = getSigningDetails(
+ input,
splitCodePaths[i],
skipVerify,
pkg.isStaticSharedLibrary(),
signingDetails,
pkg.getTargetSdkVersion()
);
+ if (result.isError()) {
+ throw new PackageParser.PackageParserException(result.getErrorCode(),
+ result.getErrorMessage(), result.getException());
+ }
+
+
+ signingDetails = result.getResult();
}
}
return signingDetails;
@@ -2657,9 +2703,10 @@ public class ParsingPackageUtils {
}
}
- public static SigningDetails collectCertificates(String baseCodePath, boolean skipVerify,
- boolean isStaticSharedLibrary, @NonNull SigningDetails existingSigningDetails,
- int targetSdk) throws PackageParserException {
+ @CheckResult
+ public static ParseResult<SigningDetails> getSigningDetails(ParseInput input,
+ String baseCodePath, boolean skipVerify, boolean isStaticSharedLibrary,
+ @NonNull SigningDetails existingSigningDetails, int targetSdk) {
int minSignatureScheme = ApkSignatureVerifier.getMinimumSignatureSchemeVersionForTargetSdk(
targetSdk);
if (isStaticSharedLibrary) {
@@ -2667,27 +2714,31 @@ public class ParsingPackageUtils {
minSignatureScheme = SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V2;
}
SigningDetails verified;
- if (skipVerify) {
- // systemDir APKs are already trusted, save time by not verifying
- verified = ApkSignatureVerifier.unsafeGetCertsWithoutVerification(
- baseCodePath, minSignatureScheme);
- } else {
- verified = ApkSignatureVerifier.verify(baseCodePath, minSignatureScheme);
+ try {
+ if (skipVerify) {
+ // systemDir APKs are already trusted, save time by not verifying
+ verified = ApkSignatureVerifier.unsafeGetCertsWithoutVerification(
+ baseCodePath, minSignatureScheme);
+ } else {
+ verified = ApkSignatureVerifier.verify(baseCodePath, minSignatureScheme);
+ }
+ } catch (PackageParserException e) {
+ return input.error(PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES,
+ "Failed collecting certificates for " + baseCodePath, e);
}
// Verify that entries are signed consistently with the first pkg
// we encountered. Note that for splits, certificates may have
// already been populated during an earlier parse of a base APK.
if (existingSigningDetails == SigningDetails.UNKNOWN) {
- return verified;
+ return input.success(verified);
} else {
if (!Signature.areExactMatch(existingSigningDetails.signatures, verified.signatures)) {
- throw new PackageParserException(
- INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES,
+ return input.error(INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES,
baseCodePath + " has mismatched certificates");
}
- return existingSigningDetails;
+ return input.success(existingSigningDetails);
}
}
diff --git a/core/java/android/content/pm/parsing/result/ParseTypeImpl.java b/core/java/android/content/pm/parsing/result/ParseTypeImpl.java
index 61152061ae10..91e571be3d89 100644
--- a/core/java/android/content/pm/parsing/result/ParseTypeImpl.java
+++ b/core/java/android/content/pm/parsing/result/ParseTypeImpl.java
@@ -18,12 +18,16 @@ package android.content.pm.parsing.result;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.parsing.ParsingUtils;
+import android.os.ServiceManager;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Slog;
+import com.android.internal.compat.IPlatformCompat;
import com.android.internal.util.CollectionUtils;
/** @hide */
@@ -61,6 +65,28 @@ public class ParseTypeImpl implements ParseInput, ParseResult<Object> {
private Integer mTargetSdkVersion;
/**
+ * Assumes {@link Context#PLATFORM_COMPAT_SERVICE} is available to the caller. For use
+ * with {@link android.content.pm.parsing.ApkLiteParseUtils} or similar where parsing is
+ * done outside of {@link com.android.server.pm.PackageManagerService}.
+ */
+ public static ParseTypeImpl forDefaultParsing() {
+ IPlatformCompat platformCompat = IPlatformCompat.Stub.asInterface(
+ ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
+ return new ParseTypeImpl((changeId, packageName, targetSdkVersion) -> {
+ ApplicationInfo appInfo = new ApplicationInfo();
+ appInfo.packageName = packageName;
+ appInfo.targetSdkVersion = targetSdkVersion;
+ try {
+ return platformCompat.isChangeEnabled(changeId, appInfo);
+ } catch (Exception e) {
+ // This shouldn't happen, but assume enforcement if it does
+ Slog.wtf(ParsingUtils.TAG, "IPlatformCompat query failed", e);
+ return true;
+ }
+ });
+ }
+
+ /**
* @param callback if nullable, fallback to manual targetSdk > Q check
*/
public ParseTypeImpl(@NonNull Callback callback) {
diff --git a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
index 567552f66b35..6720ed6b7bf9 100644
--- a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
+++ b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
@@ -35,6 +35,9 @@ import android.content.IntentSender;
import android.content.pm.PackageInstaller.SessionParams;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PackageParser.PackageParserException;
+import android.content.pm.parsing.ParsingPackage;
+import android.content.pm.parsing.ParsingPackageUtils;
+import android.content.pm.parsing.result.ParseResult;
import android.content.res.Resources;
import android.content.res.Resources.NotFoundException;
import android.net.Uri;
@@ -300,7 +303,8 @@ public class PackageManagerTests extends AndroidTestCase {
final Intent result = localReceiver.getResult();
final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
PackageInstaller.STATUS_SUCCESS);
- assertEquals(expectedResult, status);
+ String statusMessage = result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE);
+ assertEquals(statusMessage, expectedResult, status);
} catch (IllegalArgumentException | IOException | RemoteException e) {
Log.w(TAG, "Failed to install package; path=" + inPath, e);
fail("Failed to install package; path=" + inPath + ", e=" + e);
@@ -327,13 +331,14 @@ public class PackageManagerTests extends AndroidTestCase {
return Uri.fromFile(outFile);
}
- private PackageParser.Package parsePackage(Uri packageURI) throws PackageParserException {
+ private ParsingPackage parsePackage(Uri packageURI) {
final String archiveFilePath = packageURI.getPath();
- PackageParser packageParser = new PackageParser();
- File sourceFile = new File(archiveFilePath);
- PackageParser.Package pkg = packageParser.parseMonolithicPackage(sourceFile, 0);
- packageParser = null;
- return pkg;
+ ParseResult<ParsingPackage> result = ParsingPackageUtils.parseDefaultOneTime(
+ new File(archiveFilePath), 0 /*flags*/, false /*collectCertificates*/);
+ if (result.isError()) {
+ throw new IllegalStateException(result.getErrorMessage(), result.getException());
+ }
+ return result.getResult();
}
private boolean checkSd(long pkgLen) {
@@ -417,9 +422,9 @@ public class PackageManagerTests extends AndroidTestCase {
return INSTALL_LOC_ERR;
}
- private void assertInstall(PackageParser.Package pkg, int flags, int expInstallLocation) {
+ private void assertInstall(ParsingPackage pkg, int flags, int expInstallLocation) {
try {
- String pkgName = pkg.packageName;
+ String pkgName = pkg.getPackageName();
ApplicationInfo info = getPm().getApplicationInfo(pkgName, 0);
assertNotNull(info);
assertEquals(pkgName, info.packageName);
@@ -565,20 +570,20 @@ public class PackageManagerTests extends AndroidTestCase {
class InstallParams {
Uri packageURI;
- PackageParser.Package pkg;
+ ParsingPackage pkg;
InstallParams(String outFileName, int rawResId) throws PackageParserException {
this.pkg = getParsedPackage(outFileName, rawResId);
- this.packageURI = Uri.fromFile(new File(pkg.codePath));
+ this.packageURI = Uri.fromFile(new File(pkg.getCodePath()));
}
- InstallParams(PackageParser.Package pkg) {
- this.packageURI = Uri.fromFile(new File(pkg.codePath));
+ InstallParams(ParsingPackage pkg) {
+ this.packageURI = Uri.fromFile(new File(pkg.getCodePath()));
this.pkg = pkg;
}
long getApkSize() {
- File file = new File(pkg.codePath);
+ File file = new File(pkg.getCodePath());
return file.length();
}
}
@@ -680,14 +685,12 @@ public class PackageManagerTests extends AndroidTestCase {
}
}
- private PackageParser.Package getParsedPackage(String outFileName, int rawResId)
- throws PackageParserException {
+ private ParsingPackage getParsedPackage(String outFileName, int rawResId) {
PackageManager pm = mContext.getPackageManager();
File filesDir = mContext.getFilesDir();
File outFile = new File(filesDir, outFileName);
Uri packageURI = getInstallablePackage(rawResId, outFile);
- PackageParser.Package pkg = parsePackage(packageURI);
- return pkg;
+ return parsePackage(packageURI);
}
/*
@@ -698,15 +701,15 @@ public class PackageManagerTests extends AndroidTestCase {
private void installFromRawResource(InstallParams ip, int flags, boolean cleanUp, boolean fail,
int result, int expInstallLocation) throws Exception {
PackageManager pm = mContext.getPackageManager();
- PackageParser.Package pkg = ip.pkg;
+ ParsingPackage pkg = ip.pkg;
Uri packageURI = ip.packageURI;
if ((flags & PackageManager.INSTALL_REPLACE_EXISTING) == 0) {
// Make sure the package doesn't exist
try {
- ApplicationInfo appInfo = pm.getApplicationInfo(pkg.packageName,
+ ApplicationInfo appInfo = pm.getApplicationInfo(pkg.getPackageName(),
PackageManager.MATCH_UNINSTALLED_PACKAGES);
- GenericReceiver receiver = new DeleteReceiver(pkg.packageName);
- invokeDeletePackage(pkg.packageName, 0, receiver);
+ GenericReceiver receiver = new DeleteReceiver(pkg.getPackageName());
+ invokeDeletePackage(pkg.getPackageName(), 0, receiver);
} catch (IllegalArgumentException | NameNotFoundException e) {
}
}
@@ -714,10 +717,10 @@ public class PackageManagerTests extends AndroidTestCase {
if (fail) {
invokeInstallPackageFail(packageURI, flags, result);
if ((flags & PackageManager.INSTALL_REPLACE_EXISTING) == 0) {
- assertNotInstalled(pkg.packageName);
+ assertNotInstalled(pkg.getPackageName());
}
} else {
- InstallReceiver receiver = new InstallReceiver(pkg.packageName);
+ InstallReceiver receiver = new InstallReceiver(pkg.getPackageName());
invokeInstallPackage(packageURI, flags, receiver, true);
// Verify installed information
assertInstall(pkg, flags, expInstallLocation);
@@ -818,15 +821,15 @@ public class PackageManagerTests extends AndroidTestCase {
Log.i(TAG, "replace=" + replace);
GenericReceiver receiver;
if (replace) {
- receiver = new ReplaceReceiver(ip.pkg.packageName);
+ receiver = new ReplaceReceiver(ip.pkg.getPackageName());
Log.i(TAG, "Creating replaceReceiver");
} else {
- receiver = new InstallReceiver(ip.pkg.packageName);
+ receiver = new InstallReceiver(ip.pkg.getPackageName());
}
try {
invokeInstallPackage(ip.packageURI, flags, receiver, true);
if (replace) {
- assertInstall(ip.pkg, flags, ip.pkg.installLocation);
+ assertInstall(ip.pkg, flags, ip.pkg.getInstallLocation());
}
} finally {
cleanUpInstall(ip);
@@ -957,20 +960,20 @@ public class PackageManagerTests extends AndroidTestCase {
public void deleteFromRawResource(int iFlags, int dFlags) throws Exception {
InstallParams ip = sampleInstallFromRawResource(iFlags, false);
boolean retainData = ((dFlags & PackageManager.DELETE_KEEP_DATA) != 0);
- GenericReceiver receiver = new DeleteReceiver(ip.pkg.packageName);
+ GenericReceiver receiver = new DeleteReceiver(ip.pkg.getPackageName());
try {
- assertTrue(invokeDeletePackage(ip.pkg.packageName, dFlags, receiver));
+ assertTrue(invokeDeletePackage(ip.pkg.getPackageName(), dFlags, receiver));
ApplicationInfo info = null;
Log.i(TAG, "okay4");
try {
- info = getPm().getApplicationInfo(ip.pkg.packageName,
+ info = getPm().getApplicationInfo(ip.pkg.getPackageName(),
PackageManager.MATCH_UNINSTALLED_PACKAGES);
} catch (NameNotFoundException e) {
info = null;
}
if (retainData) {
assertNotNull(info);
- assertEquals(info.packageName, ip.pkg.packageName);
+ assertEquals(info.packageName, ip.pkg.getPackageName());
} else {
assertNull(info);
}
@@ -998,9 +1001,9 @@ public class PackageManagerTests extends AndroidTestCase {
}
Runtime.getRuntime().gc();
try {
- cleanUpInstall(ip.pkg.packageName);
+ cleanUpInstall(ip.pkg.getPackageName());
} finally {
- File outFile = new File(ip.pkg.codePath);
+ File outFile = new File(ip.pkg.getCodePath());
if (outFile != null && outFile.exists()) {
outFile.delete();
}
@@ -1070,13 +1073,13 @@ public class PackageManagerTests extends AndroidTestCase {
InstallParams ip = installFromRawResource("install.apk", iApk,
iFlags, false,
false, -1, PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
- GenericReceiver receiver = new ReplaceReceiver(ip.pkg.packageName);
+ GenericReceiver receiver = new ReplaceReceiver(ip.pkg.getPackageName());
int replaceFlags = rFlags | PackageManager.INSTALL_REPLACE_EXISTING;
try {
InstallParams rp = installFromRawResource("install.apk", rApk,
replaceFlags, false,
false, -1, PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL);
- assertInstall(rp.pkg, replaceFlags, rp.pkg.installLocation);
+ assertInstall(rp.pkg, replaceFlags, rp.pkg.getInstallLocation());
} catch (Exception e) {
failStr("Failed with exception : " + e);
} finally {
@@ -1103,7 +1106,7 @@ public class PackageManagerTests extends AndroidTestCase {
InstallParams rp = installFromRawResource("install.apk", rApk,
replaceFlags, false,
false, -1, PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL);
- assertInstall(rp.pkg, replaceFlags, ip.pkg.installLocation);
+ assertInstall(rp.pkg, replaceFlags, ip.pkg.getInstallLocation());
} catch (Exception e) {
failStr("Failed with exception : " + e);
} finally {
@@ -1204,18 +1207,18 @@ public class PackageManagerTests extends AndroidTestCase {
// Install first
ip = installFromRawResource("install.apk", rawResId, installFlags, false,
false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
- ApplicationInfo oldAppInfo = getPm().getApplicationInfo(ip.pkg.packageName, 0);
+ ApplicationInfo oldAppInfo = getPm().getApplicationInfo(ip.pkg.getPackageName(), 0);
if (fail) {
- assertTrue(invokeMovePackageFail(ip.pkg.packageName, moveFlags, result));
- ApplicationInfo info = getPm().getApplicationInfo(ip.pkg.packageName, 0);
+ assertTrue(invokeMovePackageFail(ip.pkg.getPackageName(), moveFlags, result));
+ ApplicationInfo info = getPm().getApplicationInfo(ip.pkg.getPackageName(), 0);
assertNotNull(info);
assertEquals(oldAppInfo.flags, info.flags);
} else {
// Create receiver based on expRetCode
- MoveReceiver receiver = new MoveReceiver(ip.pkg.packageName);
- boolean retCode = invokeMovePackage(ip.pkg.packageName, moveFlags, receiver);
+ MoveReceiver receiver = new MoveReceiver(ip.pkg.getPackageName());
+ boolean retCode = invokeMovePackage(ip.pkg.getPackageName(), moveFlags, receiver);
assertTrue(retCode);
- ApplicationInfo info = getPm().getApplicationInfo(ip.pkg.packageName, 0);
+ ApplicationInfo info = getPm().getApplicationInfo(ip.pkg.getPackageName(), 0);
assertNotNull("ApplicationInfo for recently installed application should exist",
info);
if ((moveFlags & PackageManager.MOVE_INTERNAL) != 0) {
@@ -1294,9 +1297,9 @@ public class PackageManagerTests extends AndroidTestCase {
ip = installFromRawResource("install.apk", R.raw.install, installFlags, false,
false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
// Delete the package now retaining data.
- GenericReceiver receiver = new DeleteReceiver(ip.pkg.packageName);
- invokeDeletePackage(ip.pkg.packageName, PackageManager.DELETE_KEEP_DATA, receiver);
- assertTrue(invokeMovePackageFail(ip.pkg.packageName, moveFlags, result));
+ GenericReceiver receiver = new DeleteReceiver(ip.pkg.getPackageName());
+ invokeDeletePackage(ip.pkg.getPackageName(), PackageManager.DELETE_KEEP_DATA, receiver);
+ assertTrue(invokeMovePackageFail(ip.pkg.getPackageName(), moveFlags, result));
} catch (Exception e) {
failStr(e);
} finally {
@@ -1712,7 +1715,7 @@ public class PackageManagerTests extends AndroidTestCase {
ip = installFromRawResource("install.apk", iApk,
iFlags, false,
false, -1, PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
- assertInstall(ip.pkg, iFlags, ip.pkg.installLocation);
+ assertInstall(ip.pkg, iFlags, ip.pkg.getInstallLocation());
assertPermissions(BASE_PERMISSIONS_DEFINED);
// **: Upon installing package, are its permissions granted?
@@ -1722,15 +1725,15 @@ public class PackageManagerTests extends AndroidTestCase {
ip2 = installFromRawResource("install2.apk", i2Apk,
i2Flags, false,
false, -1, PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
- assertInstall(ip2.pkg, i2Flags, ip2.pkg.installLocation);
+ assertInstall(ip2.pkg, i2Flags, ip2.pkg.getInstallLocation());
assertPermissions(BASE_PERMISSIONS_USED);
// **: Upon removing but not deleting, are permissions retained?
- GenericReceiver receiver = new DeleteReceiver(ip.pkg.packageName);
+ GenericReceiver receiver = new DeleteReceiver(ip.pkg.getPackageName());
try {
- invokeDeletePackage(ip.pkg.packageName, PackageManager.DELETE_KEEP_DATA, receiver);
+ invokeDeletePackage(ip.pkg.getPackageName(), PackageManager.DELETE_KEEP_DATA, receiver);
} catch (Exception e) {
failStr(e);
}
@@ -1742,14 +1745,14 @@ public class PackageManagerTests extends AndroidTestCase {
ip = installFromRawResource("install.apk", iApk,
iFlags | PackageManager.INSTALL_REPLACE_EXISTING, false,
false, -1, PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
- assertInstall(ip.pkg, iFlags, ip.pkg.installLocation);
+ assertInstall(ip.pkg, iFlags, ip.pkg.getInstallLocation());
assertPermissions(BASE_PERMISSIONS_DEFINED);
assertPermissions(BASE_PERMISSIONS_USED);
// **: Upon deleting package, are all permissions removed?
try {
- invokeDeletePackage(ip.pkg.packageName, 0, receiver);
+ invokeDeletePackage(ip.pkg.getPackageName(), 0, receiver);
ip = null;
} catch (Exception e) {
failStr(e);
@@ -1759,9 +1762,9 @@ public class PackageManagerTests extends AndroidTestCase {
// **: Delete package using permissions; nothing to check here.
- GenericReceiver receiver2 = new DeleteReceiver(ip2.pkg.packageName);
+ GenericReceiver receiver2 = new DeleteReceiver(ip2.pkg.getPackageName());
try {
- invokeDeletePackage(ip2.pkg.packageName, 0, receiver);
+ invokeDeletePackage(ip2.pkg.getPackageName(), 0, receiver);
ip2 = null;
} catch (Exception e) {
failStr(e);
@@ -1772,7 +1775,7 @@ public class PackageManagerTests extends AndroidTestCase {
ip2 = installFromRawResource("install2.apk", i2Apk,
i2Flags, false,
false, -1, PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
- assertInstall(ip2.pkg, i2Flags, ip2.pkg.installLocation);
+ assertInstall(ip2.pkg, i2Flags, ip2.pkg.getInstallLocation());
assertPermissions(BASE_PERMISSIONS_NOTUSED);
// **: Upon installing declaring package, are sig permissions granted
@@ -1781,7 +1784,7 @@ public class PackageManagerTests extends AndroidTestCase {
ip = installFromRawResource("install.apk", iApk,
iFlags, false,
false, -1, PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
- assertInstall(ip.pkg, iFlags, ip.pkg.installLocation);
+ assertInstall(ip.pkg, iFlags, ip.pkg.getInstallLocation());
assertPermissions(BASE_PERMISSIONS_DEFINED);
assertPermissions(BASE_PERMISSIONS_SIGUSED);
@@ -1790,13 +1793,13 @@ public class PackageManagerTests extends AndroidTestCase {
ip2 = installFromRawResource("install2.apk", i2Apk,
i2Flags | PackageManager.INSTALL_REPLACE_EXISTING, false,
false, -1, PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
- assertInstall(ip2.pkg, i2Flags, ip2.pkg.installLocation);
+ assertInstall(ip2.pkg, i2Flags, ip2.pkg.getInstallLocation());
assertPermissions(BASE_PERMISSIONS_NOTUSED);
// **: Upon deleting package, are all permissions removed?
try {
- invokeDeletePackage(ip.pkg.packageName, 0, receiver);
+ invokeDeletePackage(ip.pkg.getPackageName(), 0, receiver);
ip = null;
} catch (Exception e) {
failStr(e);
@@ -1807,7 +1810,7 @@ public class PackageManagerTests extends AndroidTestCase {
// **: Delete package using permissions; nothing to check here.
try {
- invokeDeletePackage(ip2.pkg.packageName, 0, receiver);
+ invokeDeletePackage(ip2.pkg.getPackageName(), 0, receiver);
ip2 = null;
} catch (Exception e) {
failStr(e);
@@ -1862,7 +1865,7 @@ public class PackageManagerTests extends AndroidTestCase {
int rFlags = PackageManager.INSTALL_REPLACE_EXISTING;
String apk1Name = "install1.apk";
String apk2Name = "install2.apk";
- PackageParser.Package pkg1 = getParsedPackage(apk1Name, apk1);
+ ParsingPackage pkg1 = getParsedPackage(apk1Name, apk1);
try {
InstallParams ip = installFromRawResource(apk1Name, apk1, 0, false,
false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
@@ -1873,7 +1876,7 @@ public class PackageManagerTests extends AndroidTestCase {
failStr(e.getMessage());
} finally {
if (cleanUp) {
- cleanUpInstall(pkg1.packageName);
+ cleanUpInstall(pkg1.getPackageName());
}
}
return null;
@@ -2460,16 +2463,16 @@ public class PackageManagerTests extends AndroidTestCase {
File outFile = new File(filesDir, apk2Name);
int rawResId = apk2;
Uri packageURI = getInstallablePackage(rawResId, outFile);
- PackageParser.Package pkg = parsePackage(packageURI);
+ ParsingPackage pkg = parsePackage(packageURI);
try {
- getPi().uninstall(pkg.packageName,
+ getPi().uninstall(pkg.getPackageName(),
PackageManager.DELETE_ALL_USERS,
null /*statusReceiver*/);
} catch (IllegalArgumentException ignore) {
}
// Check signatures now
int match = mContext.getPackageManager().checkSignatures(
- ip.pkg.packageName, pkg.packageName);
+ ip.pkg.getPackageName(), pkg.getPackageName());
assertEquals(PackageManager.SIGNATURE_UNKNOWN_PACKAGE, match);
} finally {
cleanUpInstall(ip);
@@ -2530,13 +2533,13 @@ public class PackageManagerTests extends AndroidTestCase {
int retCode, int expMatchResult) throws Exception {
String apk1Name = "install1.apk";
String apk2Name = "install2.apk";
- PackageParser.Package pkg1 = getParsedPackage(apk1Name, apk1);
- PackageParser.Package pkg2 = getParsedPackage(apk2Name, apk2);
+ ParsingPackage pkg1 = getParsedPackage(apk1Name, apk1);
+ ParsingPackage pkg2 = getParsedPackage(apk2Name, apk2);
try {
// Clean up before testing first.
- cleanUpInstall(pkg1.packageName);
- cleanUpInstall(pkg2.packageName);
+ cleanUpInstall(pkg1.getPackageName());
+ cleanUpInstall(pkg2.getPackageName());
installFromRawResource(apk1Name, apk1, 0, false, false, -1,
PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
if (fail) {
@@ -2545,14 +2548,14 @@ public class PackageManagerTests extends AndroidTestCase {
} else {
installFromRawResource(apk2Name, apk2, 0, false, false, -1,
PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
- int match = mContext.getPackageManager().checkSignatures(pkg1.packageName,
- pkg2.packageName);
+ int match = mContext.getPackageManager().checkSignatures(pkg1.getPackageName(),
+ pkg2.getPackageName());
assertEquals(expMatchResult, match);
}
} finally {
if (cleanUp) {
- cleanUpInstall(pkg1.packageName);
- cleanUpInstall(pkg2.packageName);
+ cleanUpInstall(pkg1.getPackageName());
+ cleanUpInstall(pkg2.getPackageName());
}
}
}
@@ -2618,15 +2621,15 @@ public class PackageManagerTests extends AndroidTestCase {
false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
PackageManager pm = mContext.getPackageManager();
// Delete app2
- PackageParser.Package pkg = getParsedPackage(apk2Name, apk2);
+ ParsingPackage pkg = getParsedPackage(apk2Name, apk2);
try {
- getPi().uninstall(
- pkg.packageName, PackageManager.DELETE_ALL_USERS, null /*statusReceiver*/);
+ getPi().uninstall(pkg.getPackageName(), PackageManager.DELETE_ALL_USERS,
+ null /*statusReceiver*/);
} catch (IllegalArgumentException ignore) {
}
// Check signatures now
int match = mContext.getPackageManager().checkSignatures(
- ip1.pkg.packageName, pkg.packageName);
+ ip1.pkg.getPackageName(), pkg.getPackageName());
assertEquals(PackageManager.SIGNATURE_UNKNOWN_PACKAGE, match);
} finally {
if (ip1 != null) {
@@ -2831,8 +2834,8 @@ public class PackageManagerTests extends AndroidTestCase {
PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
try {
// then, remove it, keeping it's data around
- final GenericReceiver receiver = new DeleteReceiver(ip.pkg.packageName);
- invokeDeletePackage(ip.pkg.packageName, PackageManager.DELETE_KEEP_DATA, receiver);
+ final GenericReceiver receiver = new DeleteReceiver(ip.pkg.getPackageName());
+ invokeDeletePackage(ip.pkg.getPackageName(), PackageManager.DELETE_KEEP_DATA, receiver);
final List<PackageInfo> packages = getPm().getInstalledPackages(flags);
assertNotNull("installed packages cannot be null", packages);
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
index a95677d0202f..5675c9986ac9 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
@@ -38,8 +38,6 @@ import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.PackageParser;
-import android.content.pm.PackageUserState;
import android.net.Uri;
import android.os.Bundle;
import android.os.Process;
@@ -526,18 +524,16 @@ public class PackageInstallerActivity extends AlertActivity {
case ContentResolver.SCHEME_FILE: {
File sourceFile = new File(packageUri.getPath());
- PackageParser.Package parsed = PackageUtil.getPackageInfo(this, sourceFile);
+ mPkgInfo = PackageUtil.getPackageInfo(this, sourceFile,
+ PackageManager.GET_PERMISSIONS);
// Check for parse errors
- if (parsed == null) {
+ if (mPkgInfo == null) {
Log.w(TAG, "Parse error when parsing manifest. Discontinuing installation");
showDialogInner(DLG_PACKAGE_ERROR);
setPmResult(PackageManager.INSTALL_FAILED_INVALID_APK);
return false;
}
- mPkgInfo = PackageParser.generatePackageInfo(parsed, null,
- PackageManager.GET_PERMISSIONS, 0, 0, null,
- new PackageUserState());
mAppSnippet = PackageUtil.getAppSnippet(this, mPkgInfo.applicationInfo, sourceFile);
} break;
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/PackageUtil.java b/packages/PackageInstaller/src/com/android/packageinstaller/PackageUtil.java
index 0e89f56d2376..d3a9f8fe1196 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/PackageUtil.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/PackageUtil.java
@@ -22,9 +22,8 @@ import android.annotation.Nullable;
import android.app.Activity;
import android.content.Context;
import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
-import android.content.pm.PackageParser;
-import android.content.pm.PackageParser.PackageParserException;
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
@@ -53,12 +52,12 @@ public class PackageUtil {
/**
* Utility method to get package information for a given {@link File}
*/
- public static PackageParser.Package getPackageInfo(Context context, File sourceFile) {
- final PackageParser parser = new PackageParser();
- parser.setCallback(new PackageParser.CallbackImpl(context.getPackageManager()));
+ @Nullable
+ public static PackageInfo getPackageInfo(Context context, File sourceFile, int flags) {
try {
- return parser.parsePackage(sourceFile, 0);
- } catch (PackageParserException e) {
+ return context.getPackageManager().getPackageArchiveInfo(sourceFile.getAbsolutePath(),
+ flags);
+ } catch (Exception ignored) {
return null;
}
}
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/wear/WearPackageInstallerService.java b/packages/PackageInstaller/src/com/android/packageinstaller/wear/WearPackageInstallerService.java
index e5f7613ab52b..06b1c1635644 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/wear/WearPackageInstallerService.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/wear/WearPackageInstallerService.java
@@ -22,11 +22,11 @@ import android.app.NotificationManager;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ApplicationInfo;
import android.content.pm.FeatureInfo;
import android.content.pm.IPackageDeleteObserver;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
-import android.content.pm.PackageParser;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
@@ -49,6 +49,7 @@ import com.android.packageinstaller.R;
import java.io.File;
import java.io.FileNotFoundException;
+import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
@@ -244,47 +245,50 @@ public class WearPackageInstallerService extends Service {
Log.e(TAG, "Could not create a temp file from FD for " + packageName);
return;
}
- PackageParser.Package pkg = PackageUtil.getPackageInfo(this, tempFile);
- if (pkg == null) {
+ PackageInfo pkgInfo = PackageUtil.getPackageInfo(this, tempFile,
+ PackageManager.GET_PERMISSIONS | PackageManager.GET_CONFIGURATIONS);
+ if (pkgInfo == null) {
Log.e(TAG, "Could not parse apk information for " + packageName);
return;
}
- if (!pkg.packageName.equals(packageName)) {
+ if (!pkgInfo.packageName.equals(packageName)) {
Log.e(TAG, "Wearable Package Name has to match what is provided for " +
packageName);
return;
}
- pkg.applicationInfo.sourceDir = tempFile.getPath();
- pkg.applicationInfo.publicSourceDir = tempFile.getPath();
+ ApplicationInfo appInfo = pkgInfo.applicationInfo;
+ appInfo.sourceDir = tempFile.getPath();
+ appInfo.publicSourceDir = tempFile.getPath();
getLabelAndUpdateNotification(packageName,
- getString(R.string.installing_app, pkg.applicationInfo.loadLabel(pm)));
+ getString(R.string.installing_app, appInfo.loadLabel(pm)));
- List<String> wearablePerms = pkg.requestedPermissions;
+ List<String> wearablePerms = Arrays.asList(pkgInfo.requestedPermissions);
// Log if the installed pkg has a higher version number.
if (existingPkgInfo != null) {
- if (existingPkgInfo.getLongVersionCode() == pkg.getLongVersionCode()) {
+ long longVersionCode = pkgInfo.getLongVersionCode();
+ if (existingPkgInfo.getLongVersionCode() == longVersionCode) {
if (skipIfSameVersion) {
- Log.w(TAG, "Version number (" + pkg.getLongVersionCode() +
+ Log.w(TAG, "Version number (" + longVersionCode +
") of new app is equal to existing app for " + packageName +
"; not installing due to versionCheck");
return;
} else {
- Log.w(TAG, "Version number of new app (" + pkg.getLongVersionCode() +
+ Log.w(TAG, "Version number of new app (" + longVersionCode +
") is equal to existing app for " + packageName);
}
- } else if (existingPkgInfo.getLongVersionCode() > pkg.getLongVersionCode()) {
+ } else if (existingPkgInfo.getLongVersionCode() > longVersionCode) {
if (skipIfLowerVersion) {
// Starting in Feldspar, we are not going to allow downgrades of any app.
- Log.w(TAG, "Version number of new app (" + pkg.getLongVersionCode() +
+ Log.w(TAG, "Version number of new app (" + longVersionCode +
") is lower than existing app ( "
+ existingPkgInfo.getLongVersionCode() +
") for " + packageName + "; not installing due to versionCheck");
return;
} else {
- Log.w(TAG, "Version number of new app (" + pkg.getLongVersionCode() +
+ Log.w(TAG, "Version number of new app (" + longVersionCode +
") is lower than existing app ( "
+ existingPkgInfo.getLongVersionCode() + ") for " + packageName);
}
@@ -309,14 +313,12 @@ public class WearPackageInstallerService extends Service {
// Check that the wearable has all the features.
boolean hasAllFeatures = true;
- if (pkg.reqFeatures != null) {
- for (FeatureInfo feature : pkg.reqFeatures) {
- if (feature.name != null && !pm.hasSystemFeature(feature.name) &&
- (feature.flags & FeatureInfo.FLAG_REQUIRED) != 0) {
- Log.e(TAG, "Wearable does not have required feature: " + feature +
- " for " + packageName);
- hasAllFeatures = false;
- }
+ for (FeatureInfo feature : pkgInfo.reqFeatures) {
+ if (feature.name != null && !pm.hasSystemFeature(feature.name) &&
+ (feature.flags & FeatureInfo.FLAG_REQUIRED) != 0) {
+ Log.e(TAG, "Wearable does not have required feature: " + feature +
+ " for " + packageName);
+ hasAllFeatures = false;
}
}
@@ -328,8 +330,8 @@ public class WearPackageInstallerService extends Service {
// wearable package.
// If the app is targeting API level 23, we will also start a service in ClockworkHome
// which will ultimately prompt the user to accept/reject permissions.
- if (checkPerms && !checkPermissions(pkg, companionSdkVersion, companionDeviceVersion,
- permUri, wearablePerms, tempFile)) {
+ if (checkPerms && !checkPermissions(pkgInfo, companionSdkVersion,
+ companionDeviceVersion, permUri, wearablePerms, tempFile)) {
Log.w(TAG, "Wearable does not have enough permissions.");
return;
}
@@ -382,7 +384,7 @@ public class WearPackageInstallerService extends Service {
}
}
- private boolean checkPermissions(PackageParser.Package pkg, int companionSdkVersion,
+ private boolean checkPermissions(PackageInfo pkgInfo, int companionSdkVersion,
int companionDeviceVersion, Uri permUri, List<String> wearablePermissions,
File apkFile) {
// Assumption: We are running on Android O.
@@ -390,12 +392,12 @@ public class WearPackageInstallerService extends Service {
// app. If the Wear App is then not targeting M, there may be permissions that are not
// granted on the Phone app (by the user) right now and we cannot just grant it for the Wear
// app.
- if (pkg.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.M) {
+ if (pkgInfo.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.M) {
// Install the app if Wear App is ready for the new perms model.
return true;
}
- if (!doesWearHaveUngrantedPerms(pkg.packageName, permUri, wearablePermissions)) {
+ if (!doesWearHaveUngrantedPerms(pkgInfo.packageName, permUri, wearablePermissions)) {
// All permissions requested by the watch are already granted on the phone, no need
// to do anything.
return true;
diff --git a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
index 2cae1d64ca34..905a10bd641b 100644
--- a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
+++ b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
@@ -571,7 +571,7 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub {
// APK signatures is already verified elsewhere in PackageManager. We do not need to
// verify it again since it could cause a timeout for large APKs.
pkg.setSigningDetails(
- ParsingPackageUtils.collectCertificates(pkg, /* skipVerify= */ true));
+ ParsingPackageUtils.getSigningDetails(pkg, /* skipVerify= */ true));
return PackageInfoUtils.generate(
pkg,
null,
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index acce6992ea79..92c145275ac8 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -509,7 +509,7 @@ public abstract class ApexManager {
ParsedPackage pp = parseResult.parsedPackage;
try {
pp.setSigningDetails(
- ParsingPackageUtils.collectCertificates(pp, false));
+ ParsingPackageUtils.getSigningDetails(pp, false));
} catch (PackageParserException e) {
throw new IllegalStateException(
"Unable to collect certificates for " + ai.modulePath, e);
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 3df044fab30d..d3f377e135cb 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -86,6 +86,8 @@ import android.content.pm.PackageParser.PackageLite;
import android.content.pm.PackageParser.PackageParserException;
import android.content.pm.dex.DexMetadataHelper;
import android.content.pm.parsing.ApkLiteParseUtils;
+import android.content.pm.parsing.result.ParseResult;
+import android.content.pm.parsing.result.ParseTypeImpl;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Binder;
@@ -2016,15 +2018,16 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
// Verify that all staged packages are internally consistent
final ArraySet<String> stagedSplits = new ArraySet<>();
+ ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
for (File addedFile : addedFiles) {
- final ApkLite apk;
- try {
- apk = ApkLiteParseUtils.parseApkLite(
- addedFile, PackageParser.PARSE_COLLECT_CERTIFICATES);
- } catch (PackageParserException e) {
- throw PackageManagerException.from(e);
+ ParseResult<ApkLite> result = ApkLiteParseUtils.parseApkLite(input.reset(),
+ addedFile, PackageParser.PARSE_COLLECT_CERTIFICATES);
+ if (result.isError()) {
+ throw new PackageManagerException(result.getErrorCode(),
+ result.getErrorMessage(), result.getException());
}
+ final ApkLite apk = result.getResult();
if (!stagedSplits.add(apk.splitName)) {
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
"Split " + apk.splitName + " was defined multiple times");
@@ -2113,16 +2116,22 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
} else {
- final PackageLite existing;
- final ApkLite existingBase;
ApplicationInfo appInfo = pkgInfo.applicationInfo;
- try {
- existing = PackageParser.parsePackageLite(new File(appInfo.getCodePath()), 0);
- existingBase = ApkLiteParseUtils.parseApkLite(new File(appInfo.getBaseCodePath()),
- PackageParser.PARSE_COLLECT_CERTIFICATES);
- } catch (PackageParserException e) {
- throw PackageManagerException.from(e);
- }
+ ParseResult<PackageLite> pkgLiteResult = ApkLiteParseUtils.parsePackageLite(
+ input.reset(), new File(appInfo.getCodePath()), 0);
+ if (pkgLiteResult.isError()) {
+ throw new PackageManagerException(PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
+ pkgLiteResult.getErrorMessage(), pkgLiteResult.getException());
+ }
+ final PackageLite existing = pkgLiteResult.getResult();
+ ParseResult<ApkLite> apkLiteResult = ApkLiteParseUtils.parseApkLite(input.reset(),
+ new File(appInfo.getBaseCodePath()),
+ PackageParser.PARSE_COLLECT_CERTIFICATES);
+ if (apkLiteResult.isError()) {
+ throw new PackageManagerException(PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
+ apkLiteResult.getErrorMessage(), apkLiteResult.getException());
+ }
+ final ApkLite existingBase = apkLiteResult.getResult();
assertApkConsistentLocked("Existing base", existingBase);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index f6758d7b4dff..f31dbbf077bb 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -223,6 +223,7 @@ import android.content.pm.VersionedPackage;
import android.content.pm.dex.ArtManager;
import android.content.pm.dex.DexMetadataHelper;
import android.content.pm.dex.IArtManager;
+import android.content.pm.parsing.ApkLiteParseUtils;
import android.content.pm.parsing.ParsingPackageUtils;
import android.content.pm.parsing.component.ParsedActivity;
import android.content.pm.parsing.component.ParsedInstrumentation;
@@ -232,6 +233,8 @@ import android.content.pm.parsing.component.ParsedPermission;
import android.content.pm.parsing.component.ParsedProcess;
import android.content.pm.parsing.component.ParsedProvider;
import android.content.pm.parsing.component.ParsedService;
+import android.content.pm.parsing.result.ParseResult;
+import android.content.pm.parsing.result.ParseTypeImpl;
import android.content.res.Resources;
import android.content.rollback.IRollbackManager;
import android.database.ContentObserver;
@@ -9057,7 +9060,7 @@ public class PackageManagerService extends IPackageManager.Stub
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates");
parsedPackage.setSigningDetails(
- ParsingPackageUtils.collectCertificates(parsedPackage, skipVerify));
+ ParsingPackageUtils.getSigningDetails(parsedPackage, skipVerify));
} catch (PackageParserException e) {
throw PackageManagerException.from(e);
} finally {
@@ -15241,12 +15244,21 @@ public class PackageManagerService extends IPackageManager.Stub
&& mIntegrityVerificationCompleted && mEnableRollbackCompleted) {
if ((installFlags & PackageManager.INSTALL_DRY_RUN) != 0) {
String packageName = "";
- try {
- PackageLite packageInfo =
- new PackageParser().parsePackageLite(origin.file, 0);
- packageName = packageInfo.packageName;
- } catch (PackageParserException e) {
- Slog.e(TAG, "Can't parse package at " + origin.file.getAbsolutePath(), e);
+ ParseResult<PackageLite> result = ApkLiteParseUtils.parsePackageLite(
+ new ParseTypeImpl(
+ (changeId, packageName1, targetSdkVersion) -> {
+ ApplicationInfo appInfo = new ApplicationInfo();
+ appInfo.packageName = packageName1;
+ appInfo.targetSdkVersion = targetSdkVersion;
+ return mPackageParserCallback.isChangeEnabled(changeId,
+ appInfo);
+ }).reset(),
+ origin.file, 0);
+ if (result.isError()) {
+ Slog.e(TAG, "Can't parse package at " + origin.file.getAbsolutePath(),
+ result.getException());
+ } else {
+ packageName = result.getResult().packageName;
}
try {
observer.onPackageInstalled(packageName, mRet, "Dry run", new Bundle());
@@ -17055,7 +17067,7 @@ public class PackageManagerService extends IPackageManager.Stub
parsedPackage.setSigningDetails(args.signingDetails);
} else {
parsedPackage.setSigningDetails(
- ParsingPackageUtils.collectCertificates(parsedPackage, false /* skipVerify */));
+ ParsingPackageUtils.getSigningDetails(parsedPackage, false /* skipVerify */));
}
} catch (PackageParserException e) {
throw new PrepareFailure("Failed collect during installPackageLI", e);
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 88f442c7b6a0..bc94528c07f0 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -51,7 +51,6 @@ import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PackageManagerInternal;
import android.content.pm.PackageParser.ApkLite;
import android.content.pm.PackageParser.PackageLite;
-import android.content.pm.PackageParser.PackageParserException;
import android.content.pm.ParceledListSlice;
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
@@ -63,6 +62,8 @@ import android.content.pm.dex.ArtManager;
import android.content.pm.dex.DexMetadataHelper;
import android.content.pm.dex.ISnapshotRuntimeProfileCallback;
import android.content.pm.parsing.ApkLiteParseUtils;
+import android.content.pm.parsing.result.ParseResult;
+import android.content.pm.parsing.result.ParseTypeImpl;
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.content.rollback.IRollbackManager;
@@ -505,6 +506,7 @@ class PackageManagerShellCommand extends ShellCommand {
long sessionSize = 0;
+ ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
for (String inPath : inPaths) {
final ParcelFileDescriptor fd = openFileForSystem(inPath, "r");
if (fd == null) {
@@ -512,12 +514,19 @@ class PackageManagerShellCommand extends ShellCommand {
throw new IllegalArgumentException("Error: Can't open file: " + inPath);
}
try {
- ApkLite baseApk = ApkLiteParseUtils.parseApkLite(fd.getFileDescriptor(), inPath, 0);
- PackageLite pkgLite = new PackageLite(null, baseApk, null, null, null, null,
- null, null);
+ ParseResult<ApkLite> apkLiteResult = ApkLiteParseUtils.parseApkLite(
+ input.reset(), fd.getFileDescriptor(), inPath, 0);
+ if (apkLiteResult.isError()) {
+ throw new IllegalArgumentException(
+ "Error: Failed to parse APK file: " + inPath + ": "
+ + apkLiteResult.getErrorMessage(),
+ apkLiteResult.getException());
+ }
+ PackageLite pkgLite = new PackageLite(null, apkLiteResult.getResult(), null, null,
+ null, null, null, null);
sessionSize += PackageHelper.calculateInstalledSize(pkgLite,
params.sessionParams.abiOverride, fd.getFileDescriptor());
- } catch (PackageParserException | IOException e) {
+ } catch (IOException e) {
getErrPrintWriter().println("Error: Failed to parse APK file: " + inPath);
throw new IllegalArgumentException(
"Error: Failed to parse APK file: " + inPath, e);
diff --git a/services/core/java/com/android/server/pm/parsing/PackageParser2.java b/services/core/java/com/android/server/pm/parsing/PackageParser2.java
index e860c4857bf4..1145057452c2 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageParser2.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageParser2.java
@@ -25,6 +25,7 @@ import android.content.pm.PackageParser;
import android.content.pm.PackageParser.PackageParserException;
import android.content.pm.parsing.ParsingPackage;
import android.content.pm.parsing.ParsingPackageUtils;
+import android.content.pm.parsing.ParsingUtils;
import android.content.pm.parsing.result.ParseInput;
import android.content.pm.parsing.result.ParseResult;
import android.content.pm.parsing.result.ParseTypeImpl;
@@ -35,7 +36,7 @@ import android.os.SystemClock;
import android.util.DisplayMetrics;
import android.util.Slog;
-import com.android.server.compat.PlatformCompat;
+import com.android.internal.compat.IPlatformCompat;
import com.android.server.pm.PackageManagerService;
import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.parsing.pkg.ParsedPackage;
@@ -58,14 +59,21 @@ public class PackageParser2 implements AutoCloseable {
*
* This must be called inside the system process as it relies on {@link ServiceManager}.
*/
+ @NonNull
public static PackageParser2 forParsingFileWithDefaults() {
- PlatformCompat platformCompat =
- (PlatformCompat) ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE);
+ IPlatformCompat platformCompat = IPlatformCompat.Stub.asInterface(
+ ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
return new PackageParser2(null /* separateProcesses */, false /* onlyCoreApps */,
null /* displayMetrics */, null /* cacheDir */, new Callback() {
@Override
public boolean isChangeEnabled(long changeId, @NonNull ApplicationInfo appInfo) {
- return platformCompat.isChangeEnabled(changeId, appInfo);
+ try {
+ return platformCompat.isChangeEnabled(changeId, appInfo);
+ } catch (Exception e) {
+ // This shouldn't happen, but assume enforcement if it does
+ Slog.wtf(ParsingUtils.TAG, "IPlatformCompat query failed", e);
+ return true;
+ }
}
@Override
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index 6726cc829c81..3336697ef359 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -37,6 +37,9 @@ import android.content.pm.PackageParser;
import android.content.pm.ParceledListSlice;
import android.content.pm.UserInfo;
import android.content.pm.VersionedPackage;
+import android.content.pm.parsing.ApkLiteParseUtils;
+import android.content.pm.parsing.result.ParseResult;
+import android.content.pm.parsing.result.ParseTypeImpl;
import android.content.rollback.IRollbackManager;
import android.content.rollback.RollbackInfo;
import android.content.rollback.RollbackManager;
@@ -791,13 +794,15 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
}
// Get information about the package to be installed.
- PackageParser.PackageLite newPackage;
- try {
- newPackage = PackageParser.parsePackageLite(new File(session.resolvedBaseCodePath), 0);
- } catch (PackageParser.PackageParserException e) {
- Slog.e(TAG, "Unable to parse new package", e);
+ ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
+ ParseResult<PackageParser.ApkLite> parseResult = ApkLiteParseUtils.parseApkLite(
+ input.reset(), new File(session.resolvedBaseCodePath), 0);
+ if (parseResult.isError()) {
+ Slog.e(TAG, "Unable to parse new package: " + parseResult.getErrorMessage(),
+ parseResult.getException());
return false;
}
+ PackageParser.ApkLite newPackage = parseResult.getResult();
String packageName = newPackage.packageName;
Slog.i(TAG, "Enabling rollback for install of " + packageName
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
index daaf870fa695..b0b5386a49bd 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
@@ -154,18 +154,7 @@ public class PackageParserTest {
@Test
public void test_serializePackage() throws Exception {
- try (PackageParser2 pp = new PackageParser2(null, false, null, mTmpDir,
- new PackageParser2.Callback() {
- @Override
- public boolean isChangeEnabled(long changeId, @NonNull ApplicationInfo appInfo) {
- return true;
- }
-
- @Override
- public boolean hasFeature(String feature) {
- return false;
- }
- })) {
+ try (PackageParser2 pp = PackageParser2.forParsingFileWithDefaults()) {
ParsedPackage pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */,
true /* useCaches */);
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexMetadataHelperTest.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexMetadataHelperTest.java
index 3888ff3e278a..caa8ae5e0e39 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/DexMetadataHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexMetadataHelperTest.java
@@ -28,8 +28,13 @@ import android.content.pm.PackageParser.ApkLite;
import android.content.pm.PackageParser.PackageLite;
import android.content.pm.PackageParser.PackageParserException;
import android.content.pm.dex.DexMetadataHelper;
+import android.content.pm.parsing.ApkLiteParseUtils;
+import android.content.pm.parsing.result.ParseInput;
+import android.content.pm.parsing.result.ParseResult;
+import android.content.pm.parsing.result.ParseTypeImpl;
import android.os.FileUtils;
+import androidx.annotation.NonNull;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -208,9 +213,12 @@ public class DexMetadataHelperTest {
throws IOException, PackageParserException {
copyApkToToTmpDir("install_split_base.apk", R.raw.install_split_base);
File dm = createDexMetadataFile("install_split_base.apk");
- PackageParser.PackageLite pkg = new PackageParser().parsePackageLite(mTmpDir,
- 0 /* flags */);
-
+ ParseResult<PackageLite> result = ApkLiteParseUtils.parsePackageLite(
+ ParseTypeImpl.forDefaultParsing().reset(), mTmpDir, 0 /* flags */);
+ if (result.isError()) {
+ throw new IllegalStateException(result.getErrorMessage(), result.getException());
+ }
+ PackageParser.PackageLite pkg = result.getResult();
Assert.assertEquals(dm.length(), DexMetadataHelper.getPackageDexMetadataSize(pkg));
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt
index 6de08fd1251f..086c845fa4b6 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt
@@ -30,10 +30,8 @@ import android.content.pm.PermissionInfo
import android.content.pm.ProviderInfo
import android.os.Debug
import android.os.Environment
-import android.os.ServiceManager
import android.util.SparseArray
import androidx.test.platform.app.InstrumentationRegistry
-import com.android.internal.compat.IPlatformCompat
import com.android.server.pm.PackageManagerService
import com.android.server.pm.PackageSetting
import com.android.server.pm.parsing.pkg.AndroidPackage
@@ -63,27 +61,7 @@ open class AndroidPackageParsingTestBase {
setCallback { false /* hasFeature */ }
}
- private val platformCompat = IPlatformCompat.Stub
- .asInterface(ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE))
-
- protected val packageParser2 = PackageParser2(null /* separateProcesses */,
- false /* onlyCoreApps */, context.resources.displayMetrics, null /* cacheDir */,
- object : PackageParser2.Callback() {
- override fun isChangeEnabled(
- changeId: Long,
- appInfo: ApplicationInfo
- ): Boolean {
- // This test queries PlatformCompat because prebuilts in the tree
- // may not be updated to be compliant with the latest enforcement checks.
- return platformCompat.isChangeEnabled(changeId, appInfo)
- }
-
- // Assume the device doesn't support anything. This will affect permission
- // parsing and will force <uses-permission/> declarations to include all
- // requiredNotFeature permissions and exclude all requiredFeature permissions.
- // This mirrors the old behavior.
- override fun hasFeature(feature: String) = false
- })
+ protected val packageParser2 = PackageParser2.forParsingFileWithDefaults()
/**
* It would be difficult to mock all possibilities, so just use the APKs on device.
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java b/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java
index 939b7a0beb49..bb223b33d8aa 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java
@@ -29,8 +29,12 @@ import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageParser;
import android.content.pm.PermissionInfo;
+import android.content.pm.parsing.PackageInfoWithoutStateUtils;
+import android.content.pm.parsing.ParsingPackage;
+import android.content.pm.parsing.ParsingPackageUtils;
import android.content.pm.parsing.component.ParsedComponent;
import android.content.pm.parsing.component.ParsedPermission;
+import android.content.pm.parsing.result.ParseResult;
import android.os.Build;
import android.os.Bundle;
import android.os.FileUtils;
@@ -518,10 +522,15 @@ public class PackageParserLegacyCoreTest {
apexInfo.versionCode = 191000070;
int flags = PackageManager.GET_META_DATA | PackageManager.GET_SIGNING_CERTIFICATES;
- PackageParser pp = new PackageParser();
- PackageParser.Package p = pp.parsePackage(apexFile, flags, false);
- PackageParser.collectCertificates(p, false);
- PackageInfo pi = PackageParser.generatePackageInfo(p, apexInfo, flags);
+ ParseResult<ParsingPackage> result = ParsingPackageUtils.parseDefaultOneTime(apexFile,
+ flags, false /*collectCertificates*/);
+ if (result.isError()) {
+ throw new IllegalStateException(result.getErrorMessage(), result.getException());
+ }
+
+ ParsingPackage pkg = result.getResult();
+ pkg.setSigningDetails(ParsingPackageUtils.getSigningDetails(pkg, false));
+ PackageInfo pi = PackageInfoWithoutStateUtils.generate(pkg, apexInfo, flags);
assertEquals("com.google.android.tzdata", pi.applicationInfo.packageName);
assertTrue(pi.applicationInfo.enabled);
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParsingDeferErrorTest.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParsingDeferErrorTest.kt
index 22487071cd71..d8910dec0bcc 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParsingDeferErrorTest.kt
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParsingDeferErrorTest.kt
@@ -64,20 +64,6 @@ class PackageParsingDeferErrorTest {
}
}
- private val parsingCallback = object : ParsingPackageUtils.Callback {
- override fun hasFeature(feature: String?) = true
-
- override fun startParsingPackage(
- packageName: String,
- baseCodePath: String,
- codePath: String,
- manifestArray: TypedArray,
- isCoreApp: Boolean
- ): ParsingPackage {
- return ParsingPackageImpl(packageName, baseCodePath, codePath, manifestArray)
- }
- }
-
@get:Rule
val tempFolder = TemporaryFolder(context.filesDir)
@@ -144,6 +130,7 @@ class PackageParsingDeferErrorTest {
input.copyTo(output)
}
}
- return ParsingPackageUtils.parseDefaultOneTime(file, 0, inputCallback, parsingCallback)
+ return ParsingPackageUtils.parseDefaultOneTime(file, 0 /*flags*/,
+ false /*collectCertificates*/)
}
}