diff options
author | TreeHugger Robot <treehugger-gerrit@google.com> | 2020-05-06 04:11:34 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2020-05-06 04:11:34 +0000 |
commit | 30de689af98bbaf2120690d1bff4e4804a621bdb (patch) | |
tree | 3e06e51a89380c7024643df500d2240255f1d47a | |
parent | 13c64e59ae5de10512e1cf2f6d3aba176130321c (diff) | |
parent | a83fad74b45e702b5fcf8cbf1b0b0bf6786bd2df (diff) |
Merge "Migrate remaining parsePackage V1 to V2" into rvc-dev am: a83fad74b4
Change-Id: Ic2c575360d3356c21b54bdeebbc66ab0b4bd6d64
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*/) } } |