Loading core/java/android/content/pm/PackageManager.java +19 −20 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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()); } /** Loading core/java/android/content/pm/PackageParser.java +4 −0 Original line number Diff line number Diff line Loading @@ -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 { Loading core/java/android/content/pm/parsing/ApkLiteParseUtils.java +143 −79 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -70,47 +74,60 @@ 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); 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); return new PackageParser.PackageLite(packagePath, baseApk, null, null, null, null, null, null); } } 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<>(); Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parseApkLite"); try { for (File file : files) { if (PackageParser.isApkFile(file)) { final PackageParser.ApkLite lite = parseApkLite(file, flags); ParseResult<PackageParser.ApkLite> result = parseApkLite(input, file, flags); if (result.isError()) { return input.error(result); } 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) { Loading @@ -118,14 +135,12 @@ public class ApkLiteParseUtils { versionCode = lite.versionCode; } else { if (!packageName.equals(lite.packageName)) { throw new PackageParser.PackageParserException( PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST, return input.error(PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST, "Inconsistent package " + lite.packageName + " in " + file + "; expected " + packageName); } if (versionCode != lite.versionCode) { throw new PackageParser.PackageParserException( PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST, return input.error(PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST, "Inconsistent version " + lite.versionCode + " in " + file + "; expected " + versionCode); } Loading @@ -133,19 +148,19 @@ public class ApkLiteParseUtils { // 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, 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); } 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); } Loading Loading @@ -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)); } /** Loading @@ -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); } /** Loading @@ -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; Loading @@ -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); } Loading @@ -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, 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); } Loading @@ -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); Loading @@ -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; Loading Loading @@ -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())) { Loading Loading @@ -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) { Loading core/java/android/content/pm/parsing/ParsingPackageUtils.java +105 −54 File changed.Preview size limit exceeded, changes collapsed. Show changes core/java/android/content/pm/parsing/result/ParseTypeImpl.java +26 −0 Original line number Diff line number Diff line Loading @@ -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 */ Loading Loading @@ -60,6 +64,28 @@ public class ParseTypeImpl implements ParseInput, ParseResult<Object> { private String mPackageName; 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 */ Loading Loading
core/java/android/content/pm/PackageManager.java +19 −20 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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()); } /** Loading
core/java/android/content/pm/PackageParser.java +4 −0 Original line number Diff line number Diff line Loading @@ -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 { Loading
core/java/android/content/pm/parsing/ApkLiteParseUtils.java +143 −79 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -70,47 +74,60 @@ 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); 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); return new PackageParser.PackageLite(packagePath, baseApk, null, null, null, null, null, null); } } 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<>(); Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parseApkLite"); try { for (File file : files) { if (PackageParser.isApkFile(file)) { final PackageParser.ApkLite lite = parseApkLite(file, flags); ParseResult<PackageParser.ApkLite> result = parseApkLite(input, file, flags); if (result.isError()) { return input.error(result); } 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) { Loading @@ -118,14 +135,12 @@ public class ApkLiteParseUtils { versionCode = lite.versionCode; } else { if (!packageName.equals(lite.packageName)) { throw new PackageParser.PackageParserException( PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST, return input.error(PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST, "Inconsistent package " + lite.packageName + " in " + file + "; expected " + packageName); } if (versionCode != lite.versionCode) { throw new PackageParser.PackageParserException( PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST, return input.error(PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST, "Inconsistent version " + lite.versionCode + " in " + file + "; expected " + versionCode); } Loading @@ -133,19 +148,19 @@ public class ApkLiteParseUtils { // 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, 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); } 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); } Loading Loading @@ -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)); } /** Loading @@ -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); } /** Loading @@ -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; Loading @@ -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); } Loading @@ -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, 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); } Loading @@ -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); Loading @@ -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; Loading Loading @@ -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())) { Loading Loading @@ -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) { Loading
core/java/android/content/pm/parsing/ParsingPackageUtils.java +105 −54 File changed.Preview size limit exceeded, changes collapsed. Show changes
core/java/android/content/pm/parsing/result/ParseTypeImpl.java +26 −0 Original line number Diff line number Diff line Loading @@ -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 */ Loading Loading @@ -60,6 +64,28 @@ public class ParseTypeImpl implements ParseInput, ParseResult<Object> { private String mPackageName; 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 */ Loading