summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWinson <chiuwinson@google.com>2020-04-17 16:24:57 -0700
committerWinson <chiuwinson@google.com>2020-05-05 16:35:34 -0700
commit3cb5610a9997313132e9dcf47f9e554dadcf4f3f (patch)
tree85ca8184b4926e377c7f927e67927938c38f9e1d
parentffc478d673931be63e86a955c924dff224324b77 (diff)
Migrate remaining parsePackage V1 to V2
Uses ParsingPackageImpl to generate the PackageInfo for PackageManager's getPackageArchiveInfo API. This keeps the migration to v2 hidden and thus the API can be shipped for this release and then deprecated entirely if necessary. Exempt-From-Owner-Approval: Has approval on previous patchsets, will need non-logic updates to resolve merge conflict and CP into rvc-dev properly Bug: 135203078 Bug: 146575910 Bug: 153880854 Test: atest com.android.server.pm.parsing Test: atest android.content.pm.PackageManagerTests Merged-In: Ib21dbbdc556502144df8e3d7a26b7a9d33885cd9 Change-Id: Ib21dbbdc556502144df8e3d7a26b7a9d33885cd9
-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 4a26587e61db..663866e89a3e 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;
@@ -9070,7 +9073,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 {
@@ -15254,12 +15257,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());
@@ -17068,7 +17080,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*/)
}
}