diff options
25 files changed, 849 insertions, 344 deletions
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 45f072adf801..fe8bf9d163c7 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -30,6 +30,7 @@ import static android.content.pm.ApplicationInfo.FLAG_SUSPENDED; import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE; import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION; import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE; +import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK; import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST; import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME; import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES; @@ -53,8 +54,6 @@ import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Intent; import android.content.IntentFilter; -import android.content.pm.split.DefaultSplitAssetLoader; -import android.content.pm.split.SplitAssetDependencyLoader; import android.content.pm.split.SplitAssetLoader; import android.content.res.ApkAssets; import android.content.res.AssetManager; @@ -80,6 +79,7 @@ import android.util.ArraySet; import android.util.AttributeSet; import android.util.Base64; import android.util.DisplayMetrics; +import android.util.IntArray; import android.util.Log; import android.util.PackageUtils; import android.util.Pair; @@ -118,6 +118,7 @@ import java.security.spec.InvalidKeySpecException; import java.security.spec.X509EncodedKeySpec; import java.util.ArrayList; import java.util.Arrays; +import java.util.BitSet; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; @@ -8573,4 +8574,410 @@ public class PackageParser { this.error = error; } } + + // Duplicate the SplitAsset related classes with PackageParser.Package/ApkLite here, and + // change the original one using new Package/ApkLite. The propose is that we don't want to + // have two branches of methods in SplitAsset related classes so we can keep real classes + // clean and move all the legacy code to one place. + + /** + * A helper class that implements the dependency tree traversal for splits. Callbacks + * are implemented by subclasses to notify whether a split has already been constructed + * and is cached, and to actually create the split requested. + * + * This helper is meant to be subclassed so as to reduce the number of allocations + * needed to make use of it. + * + * All inputs and outputs are assumed to be indices into an array of splits. + * + * @hide + * @deprecated Do not use. New changes should use + * {@link android.content.pm.split.SplitDependencyLoader} instead. + */ + @Deprecated + private abstract static class SplitDependencyLoader<E extends Exception> { + private final @NonNull SparseArray<int[]> mDependencies; + + /** + * Construct a new SplitDependencyLoader. Meant to be called from the + * subclass constructor. + * @param dependencies The dependency tree of splits. + */ + protected SplitDependencyLoader(@NonNull SparseArray<int[]> dependencies) { + mDependencies = dependencies; + } + + /** + * Traverses the dependency tree and constructs any splits that are not already + * cached. This routine short-circuits and skips the creation of splits closer to the + * root if they are cached, as reported by the subclass implementation of + * {@link #isSplitCached(int)}. The construction of splits is delegated to the subclass + * implementation of {@link #constructSplit(int, int[], int)}. + * @param splitIdx The index of the split to load. 0 represents the base Application. + */ + protected void loadDependenciesForSplit(@IntRange(from = 0) int splitIdx) throws E { + // Quick check before any allocations are done. + if (isSplitCached(splitIdx)) { + return; + } + + // Special case the base, since it has no dependencies. + if (splitIdx == 0) { + final int[] configSplitIndices = collectConfigSplitIndices(0); + constructSplit(0, configSplitIndices, -1); + return; + } + + // Build up the dependency hierarchy. + final IntArray linearDependencies = new IntArray(); + linearDependencies.add(splitIdx); + + // Collect all the dependencies that need to be constructed. + // They will be listed from leaf to root. + while (true) { + // Only follow the first index into the array. The others are config splits and + // get loaded with the split. + final int[] deps = mDependencies.get(splitIdx); + if (deps != null && deps.length > 0) { + splitIdx = deps[0]; + } else { + splitIdx = -1; + } + + if (splitIdx < 0 || isSplitCached(splitIdx)) { + break; + } + + linearDependencies.add(splitIdx); + } + + // Visit each index, from right to left (root to leaf). + int parentIdx = splitIdx; + for (int i = linearDependencies.size() - 1; i >= 0; i--) { + final int idx = linearDependencies.get(i); + final int[] configSplitIndices = collectConfigSplitIndices(idx); + constructSplit(idx, configSplitIndices, parentIdx); + parentIdx = idx; + } + } + + private @NonNull int[] collectConfigSplitIndices(int splitIdx) { + // The config splits appear after the first element. + final int[] deps = mDependencies.get(splitIdx); + if (deps == null || deps.length <= 1) { + return EmptyArray.INT; + } + return Arrays.copyOfRange(deps, 1, deps.length); + } + + /** + * Subclass to report whether the split at `splitIdx` is cached and need not be constructed. + * It is assumed that if `splitIdx` is cached, any parent of `splitIdx` is also cached. + * @param splitIdx The index of the split to check for in the cache. + * @return true if the split is cached and does not need to be constructed. + */ + protected abstract boolean isSplitCached(@IntRange(from = 0) int splitIdx); + + /** + * Subclass to construct a split at index `splitIdx` with parent split `parentSplitIdx`. + * The result is expected to be cached by the subclass in its own structures. + * @param splitIdx The index of the split to construct. 0 represents the base Application. + * @param configSplitIndices The array of configuration splits to load along with this + * split. May be empty (length == 0) but never null. + * @param parentSplitIdx The index of the parent split. -1 if there is no parent. + * @throws E Subclass defined exception representing failure to construct a split. + */ + protected abstract void constructSplit(@IntRange(from = 0) int splitIdx, + @NonNull @IntRange(from = 1) int[] configSplitIndices, + @IntRange(from = -1) int parentSplitIdx) throws E; + + public static class IllegalDependencyException extends Exception { + private IllegalDependencyException(String message) { + super(message); + } + } + + private static int[] append(int[] src, int elem) { + if (src == null) { + return new int[] { elem }; + } + int[] dst = Arrays.copyOf(src, src.length + 1); + dst[src.length] = elem; + return dst; + } + + public static @NonNull SparseArray<int[]> createDependenciesFromPackage( + PackageLite pkg) + throws SplitDependencyLoader.IllegalDependencyException { + // The data structure that holds the dependencies. In PackageParser, splits are stored + // in their own array, separate from the base. We treat all paths as equals, so + // we need to insert the base as index 0, and shift all other splits. + final SparseArray<int[]> splitDependencies = new SparseArray<>(); + + // The base depends on nothing. + splitDependencies.put(0, new int[] {-1}); + + // First write out the <uses-split> dependencies. These must appear first in the + // array of ints, as is convention in this class. + for (int splitIdx = 0; splitIdx < pkg.splitNames.length; splitIdx++) { + if (!pkg.isFeatureSplits[splitIdx]) { + // Non-feature splits don't have dependencies. + continue; + } + + // Implicit dependency on the base. + final int targetIdx; + final String splitDependency = pkg.usesSplitNames[splitIdx]; + if (splitDependency != null) { + final int depIdx = Arrays.binarySearch(pkg.splitNames, splitDependency); + if (depIdx < 0) { + throw new SplitDependencyLoader.IllegalDependencyException( + "Split '" + pkg.splitNames[splitIdx] + "' requires split '" + + splitDependency + "', which is missing."); + } + targetIdx = depIdx + 1; + } else { + // Implicitly depend on the base. + targetIdx = 0; + } + splitDependencies.put(splitIdx + 1, new int[] {targetIdx}); + } + + // Write out the configForSplit reverse-dependencies. These appear after the + // <uses-split> dependencies and are considered leaves. + // + // At this point, all splits in splitDependencies have the first element in their + // array set. + for (int splitIdx = 0, size = pkg.splitNames.length; splitIdx < size; splitIdx++) { + if (pkg.isFeatureSplits[splitIdx]) { + // Feature splits are not configForSplits. + continue; + } + + // Implicit feature for the base. + final int targetSplitIdx; + final String configForSplit = pkg.configForSplit[splitIdx]; + if (configForSplit != null) { + final int depIdx = Arrays.binarySearch(pkg.splitNames, configForSplit); + if (depIdx < 0) { + throw new SplitDependencyLoader.IllegalDependencyException( + "Split '" + pkg.splitNames[splitIdx] + "' targets split '" + + configForSplit + "', which is missing."); + } + + if (!pkg.isFeatureSplits[depIdx]) { + throw new SplitDependencyLoader.IllegalDependencyException( + "Split '" + pkg.splitNames[splitIdx] + "' declares itself as " + + "configuration split for a non-feature split '" + + pkg.splitNames[depIdx] + "'"); + } + targetSplitIdx = depIdx + 1; + } else { + targetSplitIdx = 0; + } + splitDependencies.put(targetSplitIdx, + append(splitDependencies.get(targetSplitIdx), splitIdx + 1)); + } + + // Verify that there are no cycles. + final BitSet bitset = new BitSet(); + for (int i = 0, size = splitDependencies.size(); i < size; i++) { + int splitIdx = splitDependencies.keyAt(i); + + bitset.clear(); + while (splitIdx != -1) { + // Check if this split has been visited yet. + if (bitset.get(splitIdx)) { + throw new SplitDependencyLoader.IllegalDependencyException( + "Cycle detected in split dependencies."); + } + + // Mark the split so that if we visit it again, we no there is a cycle. + bitset.set(splitIdx); + + // Follow the first dependency only, the others are leaves by definition. + final int[] deps = splitDependencies.get(splitIdx); + splitIdx = deps != null ? deps[0] : -1; + } + } + return splitDependencies; + } + } + + /** + * Loads the base and split APKs into a single AssetManager. + * @hide + * @deprecated Do not use. New changes should use + * {@link android.content.pm.split.DefaultSplitAssetLoader} instead. + */ + @Deprecated + private static class DefaultSplitAssetLoader implements SplitAssetLoader { + private final String mBaseCodePath; + private final String[] mSplitCodePaths; + private final @ParseFlags int mFlags; + private AssetManager mCachedAssetManager; + + DefaultSplitAssetLoader(PackageLite pkg, @ParseFlags int flags) { + mBaseCodePath = pkg.baseCodePath; + mSplitCodePaths = pkg.splitCodePaths; + mFlags = flags; + } + + private static ApkAssets loadApkAssets(String path, @ParseFlags int flags) + throws PackageParserException { + if ((flags & PackageParser.PARSE_MUST_BE_APK) != 0 && !PackageParser.isApkPath(path)) { + throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK, + "Invalid package file: " + path); + } + + try { + return ApkAssets.loadFromPath(path); + } catch (IOException e) { + throw new PackageParserException(INSTALL_FAILED_INVALID_APK, + "Failed to load APK at path " + path, e); + } + } + + @Override + public AssetManager getBaseAssetManager() throws PackageParserException { + if (mCachedAssetManager != null) { + return mCachedAssetManager; + } + + ApkAssets[] apkAssets = new ApkAssets[(mSplitCodePaths != null + ? mSplitCodePaths.length : 0) + 1]; + + // Load the base. + int splitIdx = 0; + apkAssets[splitIdx++] = loadApkAssets(mBaseCodePath, mFlags); + + // Load any splits. + if (!ArrayUtils.isEmpty(mSplitCodePaths)) { + for (String apkPath : mSplitCodePaths) { + apkAssets[splitIdx++] = loadApkAssets(apkPath, mFlags); + } + } + + AssetManager assets = new AssetManager(); + assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + Build.VERSION.RESOURCES_SDK_INT); + assets.setApkAssets(apkAssets, false /*invalidateCaches*/); + + mCachedAssetManager = assets; + return mCachedAssetManager; + } + + @Override + public AssetManager getSplitAssetManager(int splitIdx) throws PackageParserException { + return getBaseAssetManager(); + } + + @Override + public void close() throws Exception { + IoUtils.closeQuietly(mCachedAssetManager); + } + } + + /** + * Loads AssetManagers for splits and their dependencies. This SplitAssetLoader implementation + * is to be used when an application opts-in to isolated split loading. + * @hide + * @deprecated Do not use. New changes should use + * {@link android.content.pm.split.SplitAssetDependencyLoader} instead. + */ + @Deprecated + private static class SplitAssetDependencyLoader extends + SplitDependencyLoader<PackageParserException> implements SplitAssetLoader { + private final String[] mSplitPaths; + private final @ParseFlags int mFlags; + private final ApkAssets[][] mCachedSplitApks; + private final AssetManager[] mCachedAssetManagers; + + SplitAssetDependencyLoader(PackageLite pkg, + SparseArray<int[]> dependencies, @ParseFlags int flags) { + super(dependencies); + + // The base is inserted into index 0, so we need to shift all the splits by 1. + mSplitPaths = new String[pkg.splitCodePaths.length + 1]; + mSplitPaths[0] = pkg.baseCodePath; + System.arraycopy(pkg.splitCodePaths, 0, mSplitPaths, 1, pkg.splitCodePaths.length); + + mFlags = flags; + mCachedSplitApks = new ApkAssets[mSplitPaths.length][]; + mCachedAssetManagers = new AssetManager[mSplitPaths.length]; + } + + @Override + protected boolean isSplitCached(int splitIdx) { + return mCachedAssetManagers[splitIdx] != null; + } + + private static ApkAssets loadApkAssets(String path, @ParseFlags int flags) + throws PackageParserException { + if ((flags & PackageParser.PARSE_MUST_BE_APK) != 0 && !PackageParser.isApkPath(path)) { + throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK, + "Invalid package file: " + path); + } + + try { + return ApkAssets.loadFromPath(path); + } catch (IOException e) { + throw new PackageParserException(PackageManager.INSTALL_FAILED_INVALID_APK, + "Failed to load APK at path " + path, e); + } + } + + private static AssetManager createAssetManagerWithAssets(ApkAssets[] apkAssets) { + final AssetManager assets = new AssetManager(); + assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + Build.VERSION.RESOURCES_SDK_INT); + assets.setApkAssets(apkAssets, false /*invalidateCaches*/); + return assets; + } + + @Override + protected void constructSplit(int splitIdx, @NonNull int[] configSplitIndices, + int parentSplitIdx) throws PackageParserException { + final ArrayList<ApkAssets> assets = new ArrayList<>(); + + // Include parent ApkAssets. + if (parentSplitIdx >= 0) { + Collections.addAll(assets, mCachedSplitApks[parentSplitIdx]); + } + + // Include this ApkAssets. + assets.add(loadApkAssets(mSplitPaths[splitIdx], mFlags)); + + // Load and include all config splits for this feature. + for (int configSplitIdx : configSplitIndices) { + assets.add(loadApkAssets(mSplitPaths[configSplitIdx], mFlags)); + } + + // Cache the results. + mCachedSplitApks[splitIdx] = assets.toArray(new ApkAssets[assets.size()]); + mCachedAssetManagers[splitIdx] = createAssetManagerWithAssets( + mCachedSplitApks[splitIdx]); + } + + @Override + public AssetManager getBaseAssetManager() throws PackageParserException { + loadDependenciesForSplit(0); + return mCachedAssetManagers[0]; + } + + @Override + public AssetManager getSplitAssetManager(int idx) throws PackageParserException { + // Since we insert the base at position 0, and PackageParser keeps splits separate from + // the base, we need to adjust the index. + loadDependenciesForSplit(idx + 1); + return mCachedAssetManagers[idx + 1]; + } + + @Override + public void close() throws Exception { + for (AssetManager assets : mCachedAssetManagers) { + IoUtils.closeQuietly(assets); + } + } + } } diff --git a/core/java/android/content/pm/dex/DexMetadataHelper.java b/core/java/android/content/pm/dex/DexMetadataHelper.java index 982fce918366..bf35c4d92d3a 100644 --- a/core/java/android/content/pm/dex/DexMetadataHelper.java +++ b/core/java/android/content/pm/dex/DexMetadataHelper.java @@ -17,11 +17,11 @@ package android.content.pm.dex; import static android.content.pm.PackageManager.INSTALL_FAILED_BAD_DEX_METADATA; -import static android.content.pm.PackageParser.APK_FILE_EXTENSION; +import static android.content.pm.parsing.ApkLiteParseUtils.APK_FILE_EXTENSION; -import android.content.pm.PackageParser; -import android.content.pm.PackageParser.PackageLite; import android.content.pm.PackageParser.PackageParserException; +import android.content.pm.parsing.ApkLiteParseUtils; +import android.content.pm.parsing.PackageLite; import android.util.ArrayMap; import android.util.jar.StrictJarFile; @@ -87,7 +87,7 @@ public class DexMetadataHelper { * NOTE: involves I/O checks. */ private static Map<String, String> getPackageDexMetadata(PackageLite pkg) { - return buildPackageApkToDexMetadataMap(pkg.getAllCodePaths()); + return buildPackageApkToDexMetadataMap(pkg.getAllApkPaths()); } /** @@ -125,7 +125,7 @@ public class DexMetadataHelper { * @throws IllegalArgumentException if the code path is not an .apk. */ public static String buildDexMetadataPathForApk(String codePath) { - if (!PackageParser.isApkPath(codePath)) { + if (!ApkLiteParseUtils.isApkPath(codePath)) { throw new IllegalStateException( "Corrupted package. Code path is not an apk " + codePath); } @@ -140,7 +140,7 @@ public class DexMetadataHelper { * extension (e.g. 'foo.dm' will match 'foo' or 'foo.apk'). */ private static String buildDexMetadataPathForFile(File targetFile) { - return PackageParser.isApkFile(targetFile) + return ApkLiteParseUtils.isApkFile(targetFile) ? buildDexMetadataPathForApk(targetFile.getPath()) : targetFile.getPath() + DEX_METADATA_FILE_EXTENSION; } @@ -179,7 +179,7 @@ public class DexMetadataHelper { public static void validateDexPaths(String[] paths) { ArrayList<String> apks = new ArrayList<>(); for (int i = 0; i < paths.length; i++) { - if (PackageParser.isApkPath(paths[i])) { + if (ApkLiteParseUtils.isApkPath(paths[i])) { apks.add(paths[i]); } } diff --git a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java index 51b81b60a825..a3c2cbc56652 100644 --- a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java +++ b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java @@ -66,6 +66,8 @@ public class ApkLiteParseUtils { private static final int PARSE_DEFAULT_INSTALL_LOCATION = PackageInfo.INSTALL_LOCATION_UNSPECIFIED; + private static final Comparator<String> sSplitNameComparator = new SplitNameComparator(); + public static final String APK_FILE_EXTENSION = ".apk"; /** @@ -79,7 +81,7 @@ public class ApkLiteParseUtils { * * @see PackageParser#parsePackage(File, int) */ - public static ParseResult<PackageParser.PackageLite> parsePackageLite(ParseInput input, + public static ParseResult<PackageLite> parsePackageLite(ParseInput input, File packageFile, int flags) { if (packageFile.isDirectory()) { return parseClusterPackageLite(input, packageFile, flags); @@ -88,26 +90,32 @@ public class ApkLiteParseUtils { } } - public static ParseResult<PackageParser.PackageLite> parseMonolithicPackageLite( - ParseInput input, File packageFile, int flags) { + /** + * Parse lightweight details about a single APK files. + */ + public static ParseResult<PackageLite> parseMonolithicPackageLite(ParseInput input, + File packageFile, int flags) { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parseApkLite"); try { - ParseResult<PackageParser.ApkLite> result = parseApkLite(input, packageFile, flags); + final ParseResult<ApkLite> result = parseApkLite(input, packageFile, flags); if (result.isError()) { return input.error(result); } - final PackageParser.ApkLite baseApk = result.getResult(); + final ApkLite baseApk = result.getResult(); final String packagePath = packageFile.getAbsolutePath(); return input.success( - new PackageParser.PackageLite(packagePath, baseApk.codePath, baseApk, null, + new PackageLite(packagePath, baseApk.getPath(), baseApk, null, null, null, null, null, null)); } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } } - public static ParseResult<PackageParser.PackageLite> parseClusterPackageLite(ParseInput input, + /** + * Parse lightweight details about a directory of APKs. + */ + public static ParseResult<PackageLite> parseClusterPackageLite(ParseInput input, File packageDir, int flags) { final File[] files = packageDir.listFiles(); if (ArrayUtils.isEmpty(files)) { @@ -122,39 +130,39 @@ public class ApkLiteParseUtils { String packageName = null; int versionCode = 0; - final ArrayMap<String, PackageParser.ApkLite> apks = new ArrayMap<>(); + final ArrayMap<String, ApkLite> apks = new ArrayMap<>(); 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 (isApkFile(file)) { + final ParseResult<ApkLite> result = parseApkLite(input, file, flags); if (result.isError()) { return input.error(result); } - final PackageParser.ApkLite lite = result.getResult(); + final 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; + packageName = lite.getPackageName(); + versionCode = lite.getVersionCode(); } else { - if (!packageName.equals(lite.packageName)) { + if (!packageName.equals(lite.getPackageName())) { return input.error(PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST, - "Inconsistent package " + lite.packageName + " in " + file + "Inconsistent package " + lite.getPackageName() + " in " + file + "; expected " + packageName); } - if (versionCode != lite.versionCode) { + if (versionCode != lite.getVersionCode()) { return input.error(PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST, - "Inconsistent version " + lite.versionCode + " in " + file + "Inconsistent version " + lite.getVersionCode() + " in " + file + "; expected " + versionCode); } } // Assert that each split is defined only oncuses-static-libe - if (apks.put(lite.splitName, lite) != null) { + if (apks.put(lite.getSplitName(), lite) != null) { return input.error(PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST, - "Split name " + lite.splitName + "Split name " + lite.getSplitName() + " defined more than once; most recent was " + file); } } @@ -163,7 +171,7 @@ public class ApkLiteParseUtils { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } - final PackageParser.ApkLite baseApk = apks.remove(null); + final ApkLite baseApk = apks.remove(null); return composePackageLiteFromApks(input, packageDir, baseApk, apks); } @@ -176,9 +184,8 @@ public class ApkLiteParseUtils { * @param splitApks Parsed split APKs * @return PackageLite */ - public static ParseResult<PackageParser.PackageLite> composePackageLiteFromApks( - ParseInput input, File packageDir, PackageParser.ApkLite baseApk, - ArrayMap<String, PackageParser.ApkLite> splitApks) { + public static ParseResult<PackageLite> composePackageLiteFromApks(ParseInput input, + File packageDir, ApkLite baseApk, ArrayMap<String, ApkLite> splitApks) { return composePackageLiteFromApks(input, packageDir, baseApk, splitApks, false); } @@ -192,9 +199,9 @@ public class ApkLiteParseUtils { * @param apkRenamed Indicate whether the APKs are renamed after parsed. * @return PackageLite */ - public static ParseResult<PackageParser.PackageLite> composePackageLiteFromApks( - ParseInput input, File packageDir, PackageParser.ApkLite baseApk, - ArrayMap<String, PackageParser.ApkLite> splitApks, boolean apkRenamed) { + public static ParseResult<PackageLite> composePackageLiteFromApks( + ParseInput input, File packageDir, ApkLite baseApk, + ArrayMap<String, ApkLite> splitApks, boolean apkRenamed) { if (baseApk == null) { return input.error(PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST, "Missing base APK in " + packageDir); @@ -217,26 +224,25 @@ public class ApkLiteParseUtils { splitRevisionCodes = new int[size]; splitNames = splitApks.keySet().toArray(splitNames); - Arrays.sort(splitNames, PackageParser.sSplitNameComparator); + Arrays.sort(splitNames, sSplitNameComparator); for (int i = 0; i < size; i++) { - final PackageParser.ApkLite apk = splitApks.get(splitNames[i]); - usesSplitNames[i] = apk.usesSplitName; - isFeatureSplits[i] = apk.isFeatureSplit; - configForSplits[i] = apk.configForSplit; + final ApkLite apk = splitApks.get(splitNames[i]); + usesSplitNames[i] = apk.getUsesSplitName(); + isFeatureSplits[i] = apk.isFeatureSplit(); + configForSplits[i] = apk.getConfigForSplit(); splitCodePaths[i] = apkRenamed ? new File(packageDir, - splitNameToFileName(apk)).getAbsolutePath() : apk.codePath; - splitRevisionCodes[i] = apk.revisionCode; + splitNameToFileName(apk)).getAbsolutePath() : apk.getPath(); + splitRevisionCodes[i] = apk.getRevisionCode(); } } final String codePath = packageDir.getAbsolutePath(); final String baseCodePath = apkRenamed ? new File(packageDir, - splitNameToFileName(baseApk)).getAbsolutePath() : baseApk.codePath; + splitNameToFileName(baseApk)).getAbsolutePath() : baseApk.getPath(); return input.success( - new PackageParser.PackageLite(codePath, baseCodePath, baseApk, splitNames, - isFeatureSplits, usesSplitNames, configForSplits, splitCodePaths, - splitRevisionCodes)); + new PackageLite(codePath, baseCodePath, baseApk, splitNames, isFeatureSplits, + usesSplitNames, configForSplits, splitCodePaths, splitRevisionCodes)); } /** @@ -245,9 +251,9 @@ public class ApkLiteParseUtils { * @param apk Parsed APK * @return The canonical file name */ - public static String splitNameToFileName(@NonNull PackageParser.ApkLite apk) { + public static String splitNameToFileName(@NonNull ApkLite apk) { Objects.requireNonNull(apk); - final String fileName = apk.splitName == null ? "base" : "split_" + apk.splitName; + final String fileName = apk.getSplitName() == null ? "base" : "split_" + apk.getSplitName(); return fileName + APK_FILE_EXTENSION; } @@ -257,10 +263,9 @@ public class ApkLiteParseUtils { * * @param apkFile path to a single APK * @param flags optional parse flags, such as - * {@link PackageParser#PARSE_COLLECT_CERTIFICATES} + * {@link ParsingPackageUtils#PARSE_COLLECT_CERTIFICATES} */ - public static ParseResult<PackageParser.ApkLite> parseApkLite(ParseInput input, File apkFile, - int flags) { + public static ParseResult<ApkLite> parseApkLite(ParseInput input, File apkFile, int flags) { return parseApkLiteInner(input, apkFile, null, null, flags); } @@ -271,14 +276,14 @@ public class ApkLiteParseUtils { * @param fd already open file descriptor of an apk file * @param debugPathName arbitrary text name for this file, for debug output * @param flags optional parse flags, such as - * {@link PackageParser#PARSE_COLLECT_CERTIFICATES} + * {@link ParsingPackageUtils#PARSE_COLLECT_CERTIFICATES} */ - public static ParseResult<PackageParser.ApkLite> parseApkLite(ParseInput input, + public static ParseResult<ApkLite> parseApkLite(ParseInput input, FileDescriptor fd, String debugPathName, int flags) { return parseApkLiteInner(input, null, fd, debugPathName, flags); } - private static ParseResult<PackageParser.ApkLite> parseApkLiteInner(ParseInput input, + private static ParseResult<ApkLite> parseApkLiteInner(ParseInput input, File apkFile, FileDescriptor fd, String debugPathName, int flags) { final String apkPath = fd != null ? debugPathName : apkFile.getAbsolutePath(); @@ -294,11 +299,11 @@ public class ApkLiteParseUtils { "Failed to parse " + apkPath, e); } - parser = apkAssets.openXml(PackageParser.ANDROID_MANIFEST_FILENAME); + parser = apkAssets.openXml(ParsingPackageUtils.ANDROID_MANIFEST_FILENAME); final PackageParser.SigningDetails signingDetails; - if ((flags & PackageParser.PARSE_COLLECT_CERTIFICATES) != 0) { - final boolean skipVerify = (flags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0; + if ((flags & ParsingPackageUtils.PARSE_COLLECT_CERTIFICATES) != 0) { + final boolean skipVerify = (flags & ParsingPackageUtils.PARSE_IS_SYSTEM_DIR) != 0; Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates"); try { ParseResult<PackageParser.SigningDetails> result = @@ -335,9 +340,8 @@ public class ApkLiteParseUtils { } } - private static ParseResult<PackageParser.ApkLite> parseApkLite(ParseInput input, - String codePath, XmlPullParser parser, AttributeSet attrs, - PackageParser.SigningDetails signingDetails) + private static ParseResult<ApkLite> parseApkLite(ParseInput input, String codePath, + XmlPullParser parser, AttributeSet attrs, PackageParser.SigningDetails signingDetails) throws IOException, XmlPullParserException { ParseResult<Pair<String, String>> result = parsePackageSplitNames(input, parser, attrs); if (result.isError()) { @@ -421,12 +425,12 @@ public class ApkLiteParseUtils { continue; } - if (PackageParser.TAG_PACKAGE_VERIFIER.equals(parser.getName())) { + if (ParsingPackageUtils.TAG_PACKAGE_VERIFIER.equals(parser.getName())) { final VerifierInfo verifier = parseVerifier(attrs); if (verifier != null) { verifiers.add(verifier); } - } else if (PackageParser.TAG_APPLICATION.equals(parser.getName())) { + } else if (ParsingPackageUtils.TAG_APPLICATION.equals(parser.getName())) { for (int i = 0; i < attrs.getAttributeCount(); ++i) { final String attr = attrs.getAttributeName(i); switch (attr) { @@ -464,7 +468,7 @@ public class ApkLiteParseUtils { continue; } - if (PackageParser.TAG_PROFILEABLE.equals(parser.getName())) { + if (ParsingPackageUtils.TAG_PROFILEABLE.equals(parser.getName())) { for (int i = 0; i < attrs.getAttributeCount(); ++i) { final String attr = attrs.getAttributeName(i); if ("shell".equals(attr)) { @@ -474,7 +478,7 @@ public class ApkLiteParseUtils { } } } - } else if (PackageParser.TAG_OVERLAY.equals(parser.getName())) { + } else if (ParsingPackageUtils.TAG_OVERLAY.equals(parser.getName())) { for (int i = 0; i < attrs.getAttributeCount(); ++i) { final String attr = attrs.getAttributeName(i); if ("requiredSystemPropertyName".equals(attr)) { @@ -489,7 +493,7 @@ public class ApkLiteParseUtils { overlayPriority = attrs.getAttributeIntValue(i, 0); } } - } else if (PackageParser.TAG_USES_SPLIT.equals(parser.getName())) { + } else if (ParsingPackageUtils.TAG_USES_SPLIT.equals(parser.getName())) { if (usesSplitName != null) { Slog.w(TAG, "Only one <uses-split> permitted. Ignoring others."); continue; @@ -500,7 +504,7 @@ public class ApkLiteParseUtils { 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())) { + } else if (ParsingPackageUtils.TAG_USES_SDK.equals(parser.getName())) { for (int i = 0; i < attrs.getAttributeCount(); ++i) { final String attr = attrs.getAttributeName(i); if ("targetSdkVersion".equals(attr)) { @@ -526,8 +530,8 @@ public class ApkLiteParseUtils { } return input.success( - new PackageParser.ApkLite(codePath, packageSplit.first, packageSplit.second, - isFeatureSplit, configForSplit, usesSplitName, isSplitRequired, versionCode, + new ApkLite(codePath, packageSplit.first, packageSplit.second, isFeatureSplit, + configForSplit, usesSplitName, isSplitRequired, versionCode, versionCodeMajor, revisionCode, installLocation, verifiers, signingDetails, coreApp, debuggable, profilableByShell, multiArch, use32bitAbi, useEmbeddedDex, extractNativeLibs, isolatedSplits, targetPackage, @@ -546,7 +550,7 @@ public class ApkLiteParseUtils { return input.error(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, "No start tag found"); } - if (!parser.getName().equals(PackageParser.TAG_MANIFEST)) { + if (!parser.getName().equals(ParsingPackageUtils.TAG_MANIFEST)) { return input.error(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, "No <manifest> tag"); } @@ -625,4 +629,24 @@ public class ApkLiteParseUtils { } } } + + /** + * Check if the given file is an APK file. + * + * @param file the file to check. + * @return {@code true} if the given file is an APK file. + */ + public static boolean isApkFile(File file) { + return isApkPath(file.getName()); + } + + /** + * Check if the given path ends with APK file extension. + * + * @param path the path to check. + * @return {@code true} if the given path ends with APK file extension. + */ + public static boolean isApkPath(String path) { + return path.endsWith(APK_FILE_EXTENSION); + } } diff --git a/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java b/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java index f8fd4a539334..b7365b3eaf61 100644 --- a/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java +++ b/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java @@ -385,7 +385,7 @@ public class PackageInfoWithoutStateUtils { } // CompatibilityMode is global state. - if (!PackageParser.sCompatibilityModeEnabled) { + if (!ParsingPackageUtils.sCompatibilityModeEnabled) { ai.disableCompatibilityMode(); } diff --git a/core/java/android/content/pm/parsing/ParsingPackageImpl.java b/core/java/android/content/pm/parsing/ParsingPackageImpl.java index 38d3940ea517..51ec297df9e4 100644 --- a/core/java/android/content/pm/parsing/ParsingPackageImpl.java +++ b/core/java/android/content/pm/parsing/ParsingPackageImpl.java @@ -335,7 +335,7 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { private int fullBackupContent; private int iconRes; - private int installLocation = PackageParser.PARSE_DEFAULT_INSTALL_LOCATION; + private int installLocation = ParsingPackageUtils.PARSE_DEFAULT_INSTALL_LOCATION; private int labelRes; private int largestWidthLimitDp; private int logo; @@ -1013,7 +1013,8 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { // TODO(b/135203078): See ParsingPackageImpl#getHiddenApiEnforcementPolicy // appInfo.mHiddenApiPolicy // appInfo.hiddenUntilInstalled - appInfo.icon = (PackageParser.sUseRoundIcon && roundIconRes != 0) ? roundIconRes : iconRes; + appInfo.icon = + (ParsingPackageUtils.sUseRoundIcon && roundIconRes != 0) ? roundIconRes : iconRes; appInfo.iconRes = iconRes; appInfo.roundIconRes = roundIconRes; appInfo.installLocation = installLocation; diff --git a/core/java/android/content/pm/parsing/ParsingPackageRead.java b/core/java/android/content/pm/parsing/ParsingPackageRead.java index 13ae7a28360e..a102e828744e 100644 --- a/core/java/android/content/pm/parsing/ParsingPackageRead.java +++ b/core/java/android/content/pm/parsing/ParsingPackageRead.java @@ -66,7 +66,7 @@ public interface ParsingPackageRead extends Parcelable { /** * The names of packages to adopt ownership of permissions from, parsed under - * {@link PackageParser#TAG_ADOPT_PERMISSIONS}. + * {@link ParsingPackageUtils#TAG_ADOPT_PERMISSIONS}. * @see R.styleable#AndroidManifestOriginalPackage_name */ @NonNull @@ -105,7 +105,7 @@ public interface ParsingPackageRead extends Parcelable { /** * For use with {@link com.android.server.pm.KeySetManagerService}. Parsed in - * {@link PackageParser#TAG_KEY_SETS}. + * {@link ParsingPackageUtils#TAG_KEY_SETS}. * @see R.styleable#AndroidManifestKeySet * @see R.styleable#AndroidManifestPublicKey */ @@ -816,7 +816,7 @@ public interface ParsingPackageRead extends Parcelable { /** * For use with {@link com.android.server.pm.KeySetManagerService}. Parsed in - * {@link PackageParser#TAG_KEY_SETS}. + * {@link ParsingPackageUtils#TAG_KEY_SETS}. * @see R.styleable#AndroidManifestUpgradeKeySet */ @NonNull diff --git a/core/java/android/content/pm/parsing/ParsingPackageUtils.java b/core/java/android/content/pm/parsing/ParsingPackageUtils.java index 494b3cc1c28f..b054304bbe74 100644 --- a/core/java/android/content/pm/parsing/ParsingPackageUtils.java +++ b/core/java/android/content/pm/parsing/ParsingPackageUtils.java @@ -189,6 +189,12 @@ public class ParsingPackageUtils { PackageInfo.INSTALL_LOCATION_UNSPECIFIED; public static final int PARSE_DEFAULT_TARGET_SANDBOX = 1; + /** If set to true, we will only allow package files that exactly match + * the DTD. Otherwise, we try to get as much from the package as we + * can without failing. This should normally be set to false, to + * support extensions to the DTD in future versions. */ + public static final boolean RIGID_PARSER = false; + public static final int PARSE_MUST_BE_APK = 1 << 0; public static final int PARSE_IGNORE_PROCESSES = 1 << 1; public static final int PARSE_EXTERNAL_STORAGE = 1 << 3; @@ -220,7 +226,7 @@ public class ParsingPackageUtils { */ @NonNull public static ParseResult<ParsingPackage> parseDefaultOneTime(File file, - @PackageParser.ParseFlags int parseFlags, boolean collectCertificates) { + @ParseFlags int parseFlags, boolean collectCertificates) { ParseInput input = ParseTypeImpl.forDefaultParsing().reset(); return parseDefault(input, file, parseFlags, collectCertificates); } @@ -232,7 +238,7 @@ public class ParsingPackageUtils { */ @NonNull public static ParseResult<ParsingPackage> parseDefault(ParseInput input, File file, - @PackageParser.ParseFlags int parseFlags, boolean collectCertificates) { + @ParseFlags int parseFlags, boolean collectCertificates) { ParseResult<ParsingPackage> result; ParsingPackageUtils parser = new ParsingPackageUtils(false, null, null, new Callback() { @@ -334,14 +340,14 @@ public class ParsingPackageUtils { */ private ParseResult<ParsingPackage> parseClusterPackage(ParseInput input, File packageDir, int flags) { - ParseResult<PackageParser.PackageLite> liteResult = + final ParseResult<PackageLite> liteResult = ApkLiteParseUtils.parseClusterPackageLite(input, packageDir, 0); if (liteResult.isError()) { return input.error(liteResult); } - final PackageParser.PackageLite lite = liteResult.getResult(); - if (mOnlyCoreApps && !lite.coreApp) { + final PackageLite lite = liteResult.getResult(); + if (mOnlyCoreApps && !lite.isCoreApp()) { return input.error(INSTALL_PARSE_FAILED_ONLY_COREAPP_ALLOWED, "Not a coreApp: " + packageDir); } @@ -349,7 +355,7 @@ public class ParsingPackageUtils { // Build the split dependency tree. SparseArray<int[]> splitDependencies = null; final SplitAssetLoader assetLoader; - if (lite.isolatedSplits && !ArrayUtils.isEmpty(lite.splitNames)) { + if (lite.isIsolatedSplits() && !ArrayUtils.isEmpty(lite.getSplitNames())) { try { splitDependencies = SplitAssetDependencyLoader.createDependenciesFromPackage(lite); assetLoader = new SplitAssetDependencyLoader(lite, splitDependencies, flags); @@ -362,22 +368,22 @@ public class ParsingPackageUtils { try { final AssetManager assets = assetLoader.getBaseAssetManager(); - final File baseApk = new File(lite.baseCodePath); - ParseResult<ParsingPackage> result = parseBaseApk(input, baseApk, - lite.codePath, assets, flags); + final File baseApk = new File(lite.getBaseApkPath()); + final ParseResult<ParsingPackage> result = parseBaseApk(input, baseApk, + lite.getPath(), assets, flags); if (result.isError()) { return input.error(result); } ParsingPackage pkg = result.getResult(); - if (!ArrayUtils.isEmpty(lite.splitNames)) { + if (!ArrayUtils.isEmpty(lite.getSplitNames())) { pkg.asSplit( - lite.splitNames, - lite.splitCodePaths, - lite.splitRevisionCodes, + lite.getSplitNames(), + lite.getSplitApkPaths(), + lite.getSplitRevisionCodes(), splitDependencies ); - final int num = lite.splitNames.length; + final int num = lite.getSplitNames().length; for (int i = 0; i < num; i++) { final AssetManager splitAssets = assetLoader.getSplitAssetManager(i); @@ -385,11 +391,11 @@ public class ParsingPackageUtils { } } - pkg.setUse32BitAbi(lite.use32bitAbi); + pkg.setUse32BitAbi(lite.isUse32bitAbi()); return input.success(pkg); } catch (PackageParserException e) { return input.error(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION, - "Failed to load assets: " + lite.baseCodePath, e); + "Failed to load assets: " + lite.getBaseApkPath(), e); } finally { IoUtils.closeQuietly(assetLoader); } @@ -403,21 +409,21 @@ public class ParsingPackageUtils { */ private ParseResult<ParsingPackage> parseMonolithicPackage(ParseInput input, File apkFile, int flags) throws PackageParserException { - ParseResult<PackageParser.PackageLite> liteResult = + final ParseResult<PackageLite> liteResult = ApkLiteParseUtils.parseMonolithicPackageLite(input, apkFile, flags); if (liteResult.isError()) { return input.error(liteResult); } - final PackageParser.PackageLite lite = liteResult.getResult(); - if (mOnlyCoreApps && !lite.coreApp) { + final PackageLite lite = liteResult.getResult(); + if (mOnlyCoreApps && !lite.isCoreApp()) { return input.error(INSTALL_PARSE_FAILED_ONLY_COREAPP_ALLOWED, "Not a coreApp: " + apkFile); } final SplitAssetLoader assetLoader = new DefaultSplitAssetLoader(lite, flags); try { - ParseResult<ParsingPackage> result = parseBaseApk(input, + final ParseResult<ParsingPackage> result = parseBaseApk(input, apkFile, apkFile.getCanonicalPath(), assetLoader.getBaseAssetManager(), flags); @@ -426,7 +432,7 @@ public class ParsingPackageUtils { } return input.success(result.getResult() - .setUse32BitAbi(lite.use32bitAbi)); + .setUse32BitAbi(lite.isUse32bitAbi())); } catch (IOException e) { return input.error(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION, "Failed to get path: " + apkFile, e); @@ -440,12 +446,12 @@ public class ParsingPackageUtils { final String apkPath = apkFile.getAbsolutePath(); String volumeUuid = null; - if (apkPath.startsWith(PackageParser.MNT_EXPAND)) { - final int end = apkPath.indexOf('/', PackageParser.MNT_EXPAND.length()); - volumeUuid = apkPath.substring(PackageParser.MNT_EXPAND.length(), end); + if (apkPath.startsWith(MNT_EXPAND)) { + final int end = apkPath.indexOf('/', MNT_EXPAND.length()); + volumeUuid = apkPath.substring(MNT_EXPAND.length(), end); } - if (PackageParser.DEBUG_JAR) Slog.d(TAG, "Scanning base APK: " + apkPath); + if (DEBUG_JAR) Slog.d(TAG, "Scanning base APK: " + apkPath); final int cookie = assets.findCookieForPath(apkPath); if (cookie == 0) { @@ -454,7 +460,7 @@ public class ParsingPackageUtils { } try (XmlResourceParser parser = assets.openXmlResourceParser(cookie, - PackageParser.ANDROID_MANIFEST_FILENAME)) { + ANDROID_MANIFEST_FILENAME)) { final Resources res = new Resources(assets, mDisplayMetrics, null); ParseResult<ParsingPackage> result = parseBaseApk(input, apkPath, codePath, res, @@ -495,7 +501,7 @@ public class ParsingPackageUtils { pkg.setVolumeUuid(volumeUuid); - if ((flags & PackageParser.PARSE_COLLECT_CERTIFICATES) != 0) { + if ((flags & PARSE_COLLECT_CERTIFICATES) != 0) { pkg.setSigningDetails(getSigningDetails(pkg, false)); } else { pkg.setSigningDetails(SigningDetails.UNKNOWN); @@ -512,7 +518,7 @@ public class ParsingPackageUtils { ParsingPackage pkg, int splitIndex, AssetManager assets, int flags) { final String apkPath = pkg.getSplitCodePaths()[splitIndex]; - if (PackageParser.DEBUG_JAR) Slog.d(TAG, "Scanning split APK: " + apkPath); + if (DEBUG_JAR) Slog.d(TAG, "Scanning split APK: " + apkPath); // This must always succeed, as the path has been added to the AssetManager before. final int cookie = assets.findCookieForPath(apkPath); @@ -521,7 +527,7 @@ public class ParsingPackageUtils { "Failed adding asset path: " + apkPath); } try (XmlResourceParser parser = assets.openXmlResourceParser(cookie, - PackageParser.ANDROID_MANIFEST_FILENAME)) { + ANDROID_MANIFEST_FILENAME)) { Resources res = new Resources(assets, mDisplayMetrics, null); ParseResult<ParsingPackage> parseResult = parseSplitApk(input, pkg, res, parser, flags, splitIndex); @@ -620,9 +626,9 @@ public class ParsingPackageUtils { final ParseResult result; String tagName = parser.getName(); - if (PackageParser.TAG_APPLICATION.equals(tagName)) { + if (TAG_APPLICATION.equals(tagName)) { if (foundApp) { - if (PackageParser.RIGID_PARSER) { + if (RIGID_PARSER) { result = input.error("<manifest> has more than one <application>"); } else { Slog.w(TAG, "<manifest> has more than one <application>"); @@ -701,7 +707,7 @@ public class ParsingPackageUtils { ParseResult<ParsedActivity> activityResult = ParsedActivityUtils.parseActivityOrReceiver(mSeparateProcesses, pkg, res, - parser, flags, PackageParser.sUseRoundIcon, input); + parser, flags, sUseRoundIcon, input); if (activityResult.isSuccess()) { ParsedActivity activity = activityResult.getResult(); if (isActivity) { @@ -716,7 +722,7 @@ public class ParsingPackageUtils { case "service": ParseResult<ParsedService> serviceResult = ParsedServiceUtils.parseService( mSeparateProcesses, pkg, res, parser, flags, - PackageParser.sUseRoundIcon, input); + sUseRoundIcon, input); if (serviceResult.isSuccess()) { ParsedService service = serviceResult.getResult(); pkg.addService(service); @@ -727,7 +733,7 @@ public class ParsingPackageUtils { case "provider": ParseResult<ParsedProvider> providerResult = ParsedProviderUtils.parseProvider(mSeparateProcesses, pkg, res, parser, - flags, PackageParser.sUseRoundIcon, input); + flags, sUseRoundIcon, input); if (providerResult.isSuccess()) { ParsedProvider provider = providerResult.getResult(); pkg.addProvider(provider); @@ -737,7 +743,7 @@ public class ParsingPackageUtils { break; case "activity-alias": activityResult = ParsedActivityUtils.parseActivityAlias(pkg, res, parser, - PackageParser.sUseRoundIcon, input); + sUseRoundIcon, input); if (activityResult.isSuccess()) { ParsedActivity activity = activityResult.getResult(); pkg.addActivity(activity); @@ -815,12 +821,12 @@ public class ParsingPackageUtils { return sharedUserResult; } - pkg.setInstallLocation(anInteger(PackageParser.PARSE_DEFAULT_INSTALL_LOCATION, + pkg.setInstallLocation(anInteger(PARSE_DEFAULT_INSTALL_LOCATION, R.styleable.AndroidManifest_installLocation, sa)) - .setTargetSandboxVersion(anInteger(PackageParser.PARSE_DEFAULT_TARGET_SANDBOX, + .setTargetSandboxVersion(anInteger(PARSE_DEFAULT_TARGET_SANDBOX, R.styleable.AndroidManifest_targetSandboxVersion, sa)) /* Set the global "on SD card" flag */ - .setExternalStorage((flags & PackageParser.PARSE_EXTERNAL_STORAGE) != 0); + .setExternalStorage((flags & PARSE_EXTERNAL_STORAGE) != 0); boolean foundApp = false; final int depth = parser.getDepth(); @@ -836,9 +842,9 @@ public class ParsingPackageUtils { final ParseResult result; // <application> has special logic, so it's handled outside the general method - if (PackageParser.TAG_APPLICATION.equals(tagName)) { + if (TAG_APPLICATION.equals(tagName)) { if (foundApp) { - if (PackageParser.RIGID_PARSER) { + if (RIGID_PARSER) { result = input.error("<manifest> has more than one <application>"); } else { Slog.w(TAG, "<manifest> has more than one <application>"); @@ -897,51 +903,51 @@ public class ParsingPackageUtils { ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags) throws IOException, XmlPullParserException { switch (tag) { - case PackageParser.TAG_OVERLAY: + case TAG_OVERLAY: return parseOverlay(input, pkg, res, parser); - case PackageParser.TAG_KEY_SETS: + case TAG_KEY_SETS: return parseKeySets(input, pkg, res, parser); case "feature": // TODO moltmann: Remove - case PackageParser.TAG_ATTRIBUTION: + case TAG_ATTRIBUTION: return parseAttribution(input, pkg, res, parser); - case PackageParser.TAG_PERMISSION_GROUP: + case TAG_PERMISSION_GROUP: return parsePermissionGroup(input, pkg, res, parser); - case PackageParser.TAG_PERMISSION: + case TAG_PERMISSION: return parsePermission(input, pkg, res, parser); - case PackageParser.TAG_PERMISSION_TREE: + case TAG_PERMISSION_TREE: return parsePermissionTree(input, pkg, res, parser); - case PackageParser.TAG_USES_PERMISSION: - case PackageParser.TAG_USES_PERMISSION_SDK_M: - case PackageParser.TAG_USES_PERMISSION_SDK_23: + case TAG_USES_PERMISSION: + case TAG_USES_PERMISSION_SDK_M: + case TAG_USES_PERMISSION_SDK_23: return parseUsesPermission(input, pkg, res, parser); - case PackageParser.TAG_USES_CONFIGURATION: + case TAG_USES_CONFIGURATION: return parseUsesConfiguration(input, pkg, res, parser); - case PackageParser.TAG_USES_FEATURE: + case TAG_USES_FEATURE: return parseUsesFeature(input, pkg, res, parser); - case PackageParser.TAG_FEATURE_GROUP: + case TAG_FEATURE_GROUP: return parseFeatureGroup(input, pkg, res, parser); - case PackageParser.TAG_USES_SDK: + case TAG_USES_SDK: return parseUsesSdk(input, pkg, res, parser); - case PackageParser.TAG_SUPPORT_SCREENS: + case TAG_SUPPORT_SCREENS: return parseSupportScreens(input, pkg, res, parser); - case PackageParser.TAG_PROTECTED_BROADCAST: + case TAG_PROTECTED_BROADCAST: return parseProtectedBroadcast(input, pkg, res, parser); - case PackageParser.TAG_INSTRUMENTATION: + case TAG_INSTRUMENTATION: return parseInstrumentation(input, pkg, res, parser); - case PackageParser.TAG_ORIGINAL_PACKAGE: + case TAG_ORIGINAL_PACKAGE: return parseOriginalPackage(input, pkg, res, parser); - case PackageParser.TAG_ADOPT_PERMISSIONS: + case TAG_ADOPT_PERMISSIONS: return parseAdoptPermissions(input, pkg, res, parser); - case PackageParser.TAG_USES_GL_TEXTURE: - case PackageParser.TAG_COMPATIBLE_SCREENS: - case PackageParser.TAG_SUPPORTS_INPUT: - case PackageParser.TAG_EAT_COMMENT: + case TAG_USES_GL_TEXTURE: + case TAG_COMPATIBLE_SCREENS: + case TAG_SUPPORTS_INPUT: + case TAG_EAT_COMMENT: // Just skip this tag XmlUtils.skipCurrentTag(parser); return input.success(pkg); - case PackageParser.TAG_RESTRICT_UPDATE: + case TAG_RESTRICT_UPDATE: return parseRestrictUpdateHash(flags, input, pkg, res, parser); - case PackageParser.TAG_QUERIES: + case TAG_QUERIES: return parseQueries(input, pkg, res, parser); default: return ParsingUtils.unknownTag("<manifest>", pkg, parser, input); @@ -1125,7 +1131,7 @@ public class ParsingPackageUtils { ParsingPackage pkg, Resources res, XmlResourceParser parser) throws XmlPullParserException, IOException { ParseResult<ParsedPermissionGroup> result = ParsedPermissionUtils.parsePermissionGroup( - pkg, res, parser, PackageParser.sUseRoundIcon, input); + pkg, res, parser, sUseRoundIcon, input); if (result.isError()) { return input.error(result); } @@ -1136,7 +1142,7 @@ public class ParsingPackageUtils { ParsingPackage pkg, Resources res, XmlResourceParser parser) throws XmlPullParserException, IOException { ParseResult<ParsedPermission> result = ParsedPermissionUtils.parsePermission( - pkg, res, parser, PackageParser.sUseRoundIcon, input); + pkg, res, parser, sUseRoundIcon, input); if (result.isError()) { return input.error(result); } @@ -1147,7 +1153,7 @@ public class ParsingPackageUtils { ParsingPackage pkg, Resources res, XmlResourceParser parser) throws XmlPullParserException, IOException { ParseResult<ParsedPermission> result = ParsedPermissionUtils.parsePermissionTree( - pkg, res, parser, PackageParser.sUseRoundIcon, input); + pkg, res, parser, sUseRoundIcon, input); if (result.isError()) { return input.error(result); } @@ -1405,7 +1411,7 @@ public class ParsingPackageUtils { private static ParseResult<ParsingPackage> parseUsesSdk(ParseInput input, ParsingPackage pkg, Resources res, XmlResourceParser parser) throws IOException, XmlPullParserException { - if (PackageParser.SDK_VERSION > 0) { + if (SDK_VERSION > 0) { TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestUsesSdk); try { int minVers = 1; @@ -1440,7 +1446,7 @@ public class ParsingPackageUtils { } ParseResult<Integer> targetSdkVersionResult = computeTargetSdkVersion( - targetVers, targetCode, PackageParser.SDK_CODENAMES, input); + targetVers, targetCode, SDK_CODENAMES, input); if (targetSdkVersionResult.isError()) { return input.error(targetSdkVersionResult); } @@ -1454,7 +1460,7 @@ public class ParsingPackageUtils { } ParseResult<Integer> minSdkVersionResult = computeMinSdkVersion(minVers, minCode, - PackageParser.SDK_VERSION, PackageParser.SDK_CODENAMES, input); + SDK_VERSION, SDK_CODENAMES, input); if (minSdkVersionResult.isError()) { return input.error(minSdkVersionResult); } @@ -1637,7 +1643,7 @@ public class ParsingPackageUtils { private static ParseResult<ParsingPackage> parseRestrictUpdateHash(int flags, ParseInput input, ParsingPackage pkg, Resources res, XmlResourceParser parser) { - if ((flags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0) { + if ((flags & PARSE_IS_SYSTEM_DIR) != 0) { TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestRestrictUpdate); try { final String hash = sa.getNonConfigurationString( @@ -1846,7 +1852,7 @@ public class ParsingPackageUtils { return input.error("Empty class name in package " + pkgName); } - if (PackageParser.DEBUG_BACKUP) { + if (DEBUG_BACKUP) { Slog.v(TAG, "android:backupAgent = " + backupAgentName + " from " + pkgName + "+" + backupAgent); } @@ -1870,7 +1876,7 @@ public class ParsingPackageUtils { fullBackupContent = v.resourceId; if (v.resourceId == 0) { - if (PackageParser.DEBUG_BACKUP) { + if (DEBUG_BACKUP) { Slog.v(TAG, "fullBackupContent specified as boolean=" + (v.data == 0 ? "false" : "true")); } @@ -1880,7 +1886,7 @@ public class ParsingPackageUtils { pkg.setFullBackupContent(fullBackupContent); } - if (PackageParser.DEBUG_BACKUP) { + if (DEBUG_BACKUP) { Slog.v(TAG, "fullBackupContent=" + fullBackupContent + " for " + pkgName); } } @@ -1994,7 +2000,7 @@ public class ParsingPackageUtils { case "receiver": ParseResult<ParsedActivity> activityResult = ParsedActivityUtils.parseActivityOrReceiver(mSeparateProcesses, pkg, - res, parser, flags, PackageParser.sUseRoundIcon, input); + res, parser, flags, sUseRoundIcon, input); if (activityResult.isSuccess()) { ParsedActivity activity = activityResult.getResult(); @@ -2012,7 +2018,7 @@ public class ParsingPackageUtils { case "service": ParseResult<ParsedService> serviceResult = ParsedServiceUtils.parseService(mSeparateProcesses, pkg, res, parser, - flags, PackageParser.sUseRoundIcon, input); + flags, sUseRoundIcon, input); if (serviceResult.isSuccess()) { ParsedService service = serviceResult.getResult(); hasServiceOrder |= (service.getOrder() != 0); @@ -2024,7 +2030,7 @@ public class ParsingPackageUtils { case "provider": ParseResult<ParsedProvider> providerResult = ParsedProviderUtils.parseProvider(mSeparateProcesses, pkg, res, parser, - flags, PackageParser.sUseRoundIcon, input); + flags, sUseRoundIcon, input); if (providerResult.isSuccess()) { pkg.addProvider(providerResult.getResult()); } @@ -2033,7 +2039,7 @@ public class ParsingPackageUtils { break; case "activity-alias": activityResult = ParsedActivityUtils.parseActivityAlias(pkg, res, - parser, PackageParser.sUseRoundIcon, input); + parser, sUseRoundIcon, input); if (activityResult.isSuccess()) { ParsedActivity activity = activityResult.getResult(); hasActivityOrder |= (activity.getOrder() != 0); @@ -2505,8 +2511,7 @@ public class ParsingPackageUtils { private static void setMaxAspectRatio(ParsingPackage pkg) { // Default to (1.86) 16.7:9 aspect ratio for pre-O apps and unset for O and greater. // NOTE: 16.7:9 was the max aspect ratio Android devices can support pre-O per the CDD. - float maxAspectRatio = pkg.getTargetSdkVersion() < O - ? PackageParser.DEFAULT_PRE_O_MAX_ASPECT_RATIO : 0; + float maxAspectRatio = pkg.getTargetSdkVersion() < O ? DEFAULT_PRE_O_MAX_ASPECT_RATIO : 0; float packageMaxAspectRatio = pkg.getMaxAspectRatio(); if (packageMaxAspectRatio != 0) { @@ -2514,10 +2519,8 @@ public class ParsingPackageUtils { maxAspectRatio = packageMaxAspectRatio; } else { Bundle appMetaData = pkg.getMetaData(); - if (appMetaData != null && appMetaData.containsKey( - PackageParser.METADATA_MAX_ASPECT_RATIO)) { - maxAspectRatio = appMetaData.getFloat(PackageParser.METADATA_MAX_ASPECT_RATIO, - maxAspectRatio); + if (appMetaData != null && appMetaData.containsKey(METADATA_MAX_ASPECT_RATIO)) { + maxAspectRatio = appMetaData.getFloat(METADATA_MAX_ASPECT_RATIO, maxAspectRatio); } } @@ -2536,8 +2539,7 @@ public class ParsingPackageUtils { // process the meta data here since this method is called at the end of processing // the application and all meta data is guaranteed. final float activityAspectRatio = activity.getMetaData() != null - ? activity.getMetaData().getFloat(PackageParser.METADATA_MAX_ASPECT_RATIO, - maxAspectRatio) + ? activity.getMetaData().getFloat(METADATA_MAX_ASPECT_RATIO, maxAspectRatio) : maxAspectRatio; activity.setMaxAspectRatio(activity.getResizeMode(), activityAspectRatio); @@ -2565,7 +2567,7 @@ public class ParsingPackageUtils { private void setSupportsSizeChanges(ParsingPackage pkg) { final Bundle appMetaData = pkg.getMetaData(); final boolean supportsSizeChanges = appMetaData != null - && appMetaData.getBoolean(PackageParser.METADATA_SUPPORTS_SIZE_CHANGES, false); + && appMetaData.getBoolean(METADATA_SUPPORTS_SIZE_CHANGES, false); List<ParsedActivity> activities = pkg.getActivities(); int activitiesSize = activities.size(); @@ -2573,7 +2575,7 @@ public class ParsingPackageUtils { ParsedActivity activity = activities.get(index); if (supportsSizeChanges || (activity.getMetaData() != null && activity.getMetaData().getBoolean( - PackageParser.METADATA_SUPPORTS_SIZE_CHANGES, false))) { + METADATA_SUPPORTS_SIZE_CHANGES, false))) { activity.setSupportsSizeChanges(true); } } @@ -2674,7 +2676,7 @@ public class ParsingPackageUtils { ParsingPackage pkg, Resources res, XmlResourceParser parser) throws XmlPullParserException, IOException { ParseResult<ParsedInstrumentation> result = ParsedInstrumentationUtils.parseInstrumentation( - pkg, res, parser, PackageParser.sUseRoundIcon, input); + pkg, res, parser, sUseRoundIcon, input); if (result.isError()) { return input.error(result); } @@ -2860,7 +2862,7 @@ public class ParsingPackageUtils { } else if (v.type == TypedValue.TYPE_FLOAT) { property = new Property(name, v.getFloat(), packageName, className); } else { - if (!PackageParser.RIGID_PARSER) { + if (!RIGID_PARSER) { Slog.w(TAG, tagName + " only supports string, integer, float, color, " + "boolean, and resource reference types: " diff --git a/core/java/android/content/pm/parsing/component/ComponentParseUtils.java b/core/java/android/content/pm/parsing/component/ComponentParseUtils.java index d65f8ffc989a..0403a25f5ea1 100644 --- a/core/java/android/content/pm/parsing/component/ComponentParseUtils.java +++ b/core/java/android/content/pm/parsing/component/ComponentParseUtils.java @@ -22,9 +22,9 @@ import android.annotation.AttrRes; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Intent; -import android.content.pm.PackageParser; import android.content.pm.PackageUserState; 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; @@ -77,7 +77,7 @@ public class ComponentParseUtils { @NonNull public static ParseResult<String> buildProcessName(@NonNull String pkg, String defProc, CharSequence procSeq, int flags, String[] separateProcesses, ParseInput input) { - if ((flags & PackageParser.PARSE_IGNORE_PROCESSES) != 0 && !"system".contentEquals( + if ((flags & ParsingPackageUtils.PARSE_IGNORE_PROCESSES) != 0 && !"system".contentEquals( procSeq)) { return input.success(defProc != null ? defProc : pkg); } diff --git a/core/java/android/content/pm/parsing/component/ParsedActivity.java b/core/java/android/content/pm/parsing/component/ParsedActivity.java index 19150283d71e..2ea24f71371b 100644 --- a/core/java/android/content/pm/parsing/component/ParsedActivity.java +++ b/core/java/android/content/pm/parsing/component/ParsedActivity.java @@ -28,7 +28,6 @@ import android.app.ActivityTaskManager; import android.content.ComponentName; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; -import android.content.pm.PackageParser; import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; @@ -127,7 +126,7 @@ public class ParsedActivity extends ParsedMainComponent { activity.launchMode = ActivityInfo.LAUNCH_MULTIPLE; activity.documentLaunchMode = ActivityInfo.DOCUMENT_LAUNCH_NONE; activity.maxRecents = ActivityTaskManager.getDefaultAppRecentsLimitStatic(); - activity.configChanges = PackageParser.getActivityConfigChanges(0, 0); + activity.configChanges = ParsedActivityUtils.getActivityConfigChanges(0, 0); activity.softInputMode = 0; activity.persistableMode = ActivityInfo.PERSIST_NEVER; activity.screenOrientation = SCREEN_ORIENTATION_UNSPECIFIED; diff --git a/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java b/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java index f96bd5400cd2..f821e081fc66 100644 --- a/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java +++ b/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java @@ -23,8 +23,8 @@ import android.annotation.NonNull; import android.app.ActivityTaskManager; import android.content.Intent; import android.content.pm.ActivityInfo; -import android.content.pm.PackageParser; 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.ParseInput.DeferredError; @@ -67,6 +67,12 @@ public class ParsedActivityUtils { SAFE_BROADCASTS.add(Intent.ACTION_BOOT_COMPLETED); } + /** + * Bit mask of all the valid bits that can be set in recreateOnConfigChanges. + */ + private static final int RECREATE_ON_CONFIG_CHANGES_MASK = + ActivityInfo.CONFIG_MCC | ActivityInfo.CONFIG_MNC; + @NonNull @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) public static ParseResult<ParsedActivity> parseActivityOrReceiver(String[] separateProcesses, @@ -153,7 +159,7 @@ public class ParsedActivityUtils { activity.rotationAnimation = sa.getInt(R.styleable.AndroidManifestActivity_rotationAnimation, WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED); activity.softInputMode = sa.getInt(R.styleable.AndroidManifestActivity_windowSoftInputMode, 0); - activity.configChanges = PackageParser.getActivityConfigChanges( + activity.configChanges = getActivityConfigChanges( sa.getInt(R.styleable.AndroidManifestActivity_configChanges, 0), sa.getInt(R.styleable.AndroidManifestActivity_recreateOnConfigChanges, 0)); @@ -345,7 +351,7 @@ public class ParsedActivityUtils { if (intent != null) { activity.order = Math.max(intent.getOrder(), activity.order); activity.addIntent(intent); - if (PackageParser.LOG_UNSAFE_BROADCASTS && isReceiver + if (LOG_UNSAFE_BROADCASTS && isReceiver && pkg.getTargetSdkVersion() >= Build.VERSION_CODES.O) { int actionCount = intent.countActions(); for (int i = 0; i < actionCount; i++) { @@ -354,7 +360,7 @@ public class ParsedActivityUtils { continue; } - if (!PackageParser.SAFE_BROADCASTS.contains(action)) { + if (!SAFE_BROADCASTS.contains(action)) { Slog.w(TAG, "Broadcast " + action + " may never be delivered to " + pkg.getPackageName() + " as requested at: " @@ -532,7 +538,7 @@ public class ParsedActivityUtils { ParsedActivity activity, ParseInput input) { // There isn't a metadata for us to fall back. Whatever is in layout is correct. if (activity.metaData == null || !activity.metaData.containsKey( - PackageParser.METADATA_ACTIVITY_WINDOW_LAYOUT_AFFINITY)) { + ParsingPackageUtils.METADATA_ACTIVITY_WINDOW_LAYOUT_AFFINITY)) { return input.success(activity.windowLayout); } @@ -542,7 +548,7 @@ public class ParsedActivityUtils { } String windowLayoutAffinity = activity.metaData.getString( - PackageParser.METADATA_ACTIVITY_WINDOW_LAYOUT_AFFINITY); + ParsingPackageUtils.METADATA_ACTIVITY_WINDOW_LAYOUT_AFFINITY); ActivityInfo.WindowLayout layout = activity.windowLayout; if (layout == null) { layout = new ActivityInfo.WindowLayout(-1 /* width */, -1 /* widthFraction */, @@ -553,4 +559,14 @@ public class ParsedActivityUtils { } return input.success(layout); } + + /** + * @param configChanges The bit mask of configChanges fetched from AndroidManifest.xml. + * @param recreateOnConfigChanges The bit mask recreateOnConfigChanges fetched from + * AndroidManifest.xml. + * @hide + */ + static int getActivityConfigChanges(int configChanges, int recreateOnConfigChanges) { + return configChanges | ((~recreateOnConfigChanges) & RECREATE_ON_CONFIG_CHANGES_MASK); + } } diff --git a/core/java/android/content/pm/parsing/component/ParsedIntentInfoUtils.java b/core/java/android/content/pm/parsing/component/ParsedIntentInfoUtils.java index 368dcfde3267..939e77f6067c 100644 --- a/core/java/android/content/pm/parsing/component/ParsedIntentInfoUtils.java +++ b/core/java/android/content/pm/parsing/component/ParsedIntentInfoUtils.java @@ -21,6 +21,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageParser; 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; @@ -65,7 +66,7 @@ public class ParsedIntentInfoUtils { } } - if (PackageParser.sUseRoundIcon) { + if (ParsingPackageUtils.sUseRoundIcon) { intentInfo.icon = sa.getResourceId( R.styleable.AndroidManifestIntentFilter_roundIcon, 0); } @@ -141,7 +142,7 @@ public class ParsedIntentInfoUtils { intentInfo.hasDefault = intentInfo.hasCategory(Intent.CATEGORY_DEFAULT); - if (PackageParser.DEBUG_PARSER) { + if (DEBUG) { final StringBuilder cats = new StringBuilder("Intent d="); cats.append(intentInfo.isHasDefault()); cats.append(", cat="); diff --git a/core/java/android/content/pm/split/DefaultSplitAssetLoader.java b/core/java/android/content/pm/split/DefaultSplitAssetLoader.java index 9e3a8f48996c..f3caf603921f 100644 --- a/core/java/android/content/pm/split/DefaultSplitAssetLoader.java +++ b/core/java/android/content/pm/split/DefaultSplitAssetLoader.java @@ -18,9 +18,11 @@ package android.content.pm.split; import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK; import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NOT_APK; -import android.content.pm.PackageParser; import android.content.pm.PackageParser.PackageParserException; -import android.content.pm.PackageParser.ParseFlags; +import android.content.pm.parsing.ApkLiteParseUtils; +import android.content.pm.parsing.PackageLite; +import android.content.pm.parsing.ParsingPackageUtils; +import android.content.pm.parsing.ParsingPackageUtils.ParseFlags; import android.content.res.ApkAssets; import android.content.res.AssetManager; import android.os.Build; @@ -36,20 +38,21 @@ import java.io.IOException; * @hide */ public class DefaultSplitAssetLoader implements SplitAssetLoader { - private final String mBaseCodePath; - private final String[] mSplitCodePaths; + private final String mBaseApkPath; + private final String[] mSplitApkPaths; private final @ParseFlags int mFlags; private AssetManager mCachedAssetManager; - public DefaultSplitAssetLoader(PackageParser.PackageLite pkg, @ParseFlags int flags) { - mBaseCodePath = pkg.baseCodePath; - mSplitCodePaths = pkg.splitCodePaths; + public DefaultSplitAssetLoader(PackageLite pkg, @ParseFlags int flags) { + mBaseApkPath = pkg.getBaseApkPath(); + mSplitApkPaths = pkg.getSplitApkPaths(); mFlags = flags; } private static ApkAssets loadApkAssets(String path, @ParseFlags int flags) throws PackageParserException { - if ((flags & PackageParser.PARSE_MUST_BE_APK) != 0 && !PackageParser.isApkPath(path)) { + if ((flags & ParsingPackageUtils.PARSE_MUST_BE_APK) != 0 + && !ApkLiteParseUtils.isApkPath(path)) { throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK, "Invalid package file: " + path); } @@ -68,16 +71,16 @@ public class DefaultSplitAssetLoader implements SplitAssetLoader { return mCachedAssetManager; } - ApkAssets[] apkAssets = new ApkAssets[(mSplitCodePaths != null - ? mSplitCodePaths.length : 0) + 1]; + ApkAssets[] apkAssets = new ApkAssets[(mSplitApkPaths != null + ? mSplitApkPaths.length : 0) + 1]; // Load the base. int splitIdx = 0; - apkAssets[splitIdx++] = loadApkAssets(mBaseCodePath, mFlags); + apkAssets[splitIdx++] = loadApkAssets(mBaseApkPath, mFlags); // Load any splits. - if (!ArrayUtils.isEmpty(mSplitCodePaths)) { - for (String apkPath : mSplitCodePaths) { + if (!ArrayUtils.isEmpty(mSplitApkPaths)) { + for (String apkPath : mSplitApkPaths) { apkAssets[splitIdx++] = loadApkAssets(apkPath, mFlags); } } diff --git a/core/java/android/content/pm/split/SplitAssetDependencyLoader.java b/core/java/android/content/pm/split/SplitAssetDependencyLoader.java index 58eaabfa62f2..523ca405eec7 100644 --- a/core/java/android/content/pm/split/SplitAssetDependencyLoader.java +++ b/core/java/android/content/pm/split/SplitAssetDependencyLoader.java @@ -19,9 +19,11 @@ import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NOT_APK; import android.annotation.NonNull; import android.content.pm.PackageManager; -import android.content.pm.PackageParser; import android.content.pm.PackageParser.PackageParserException; -import android.content.pm.PackageParser.ParseFlags; +import android.content.pm.parsing.ApkLiteParseUtils; +import android.content.pm.parsing.PackageLite; +import android.content.pm.parsing.ParsingPackageUtils; +import android.content.pm.parsing.ParsingPackageUtils.ParseFlags; import android.content.res.ApkAssets; import android.content.res.AssetManager; import android.os.Build; @@ -45,14 +47,14 @@ public class SplitAssetDependencyLoader extends SplitDependencyLoader<PackagePar private final ApkAssets[][] mCachedSplitApks; private final AssetManager[] mCachedAssetManagers; - public SplitAssetDependencyLoader(PackageParser.PackageLite pkg, + public SplitAssetDependencyLoader(PackageLite pkg, SparseArray<int[]> dependencies, @ParseFlags int flags) { super(dependencies); // The base is inserted into index 0, so we need to shift all the splits by 1. - mSplitPaths = new String[pkg.splitCodePaths.length + 1]; - mSplitPaths[0] = pkg.baseCodePath; - System.arraycopy(pkg.splitCodePaths, 0, mSplitPaths, 1, pkg.splitCodePaths.length); + mSplitPaths = new String[pkg.getSplitApkPaths().length + 1]; + mSplitPaths[0] = pkg.getBaseApkPath(); + System.arraycopy(pkg.getSplitApkPaths(), 0, mSplitPaths, 1, pkg.getSplitApkPaths().length); mFlags = flags; mCachedSplitApks = new ApkAssets[mSplitPaths.length][]; @@ -66,7 +68,8 @@ public class SplitAssetDependencyLoader extends SplitDependencyLoader<PackagePar private static ApkAssets loadApkAssets(String path, @ParseFlags int flags) throws PackageParserException { - if ((flags & PackageParser.PARSE_MUST_BE_APK) != 0 && !PackageParser.isApkPath(path)) { + if ((flags & ParsingPackageUtils.PARSE_MUST_BE_APK) != 0 + && !ApkLiteParseUtils.isApkPath(path)) { throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK, "Invalid package file: " + path); } diff --git a/core/java/android/content/pm/split/SplitDependencyLoader.java b/core/java/android/content/pm/split/SplitDependencyLoader.java index 358654692c9e..3e681327e0c0 100644 --- a/core/java/android/content/pm/split/SplitDependencyLoader.java +++ b/core/java/android/content/pm/split/SplitDependencyLoader.java @@ -17,7 +17,7 @@ package android.content.pm.split; import android.annotation.IntRange; import android.annotation.NonNull; -import android.content.pm.PackageParser; +import android.content.pm.parsing.PackageLite; import android.util.IntArray; import android.util.SparseArray; @@ -149,10 +149,19 @@ public abstract class SplitDependencyLoader<E extends Exception> { return dst; } - public static @NonNull SparseArray<int[]> createDependenciesFromPackage( - PackageParser.PackageLite pkg) throws IllegalDependencyException { - // The data structure that holds the dependencies. In PackageParser, splits are stored - // in their own array, separate from the base. We treat all paths as equals, so + /** + * Build the split dependency tree by the given package + * + * @param pkg The package to retrieve the dependency tree + * @return The dependency tree of splits + * @throws IllegalDependencyException if the requires split is missing, targets split is + * missing, it declares itself as configuration split for a non-feature split, or + * cycle detected in split dependencies. + */ + public static @NonNull SparseArray<int[]> createDependenciesFromPackage(PackageLite pkg) + throws IllegalDependencyException { + // The data structure that holds the dependencies. In ParsingPackageUtils, splits are + // stored in their own array, separate from the base. We treat all paths as equals, so // we need to insert the base as index 0, and shift all other splits. final SparseArray<int[]> splitDependencies = new SparseArray<>(); @@ -161,19 +170,19 @@ public abstract class SplitDependencyLoader<E extends Exception> { // First write out the <uses-split> dependencies. These must appear first in the // array of ints, as is convention in this class. - for (int splitIdx = 0; splitIdx < pkg.splitNames.length; splitIdx++) { - if (!pkg.isFeatureSplits[splitIdx]) { + for (int splitIdx = 0; splitIdx < pkg.getSplitNames().length; splitIdx++) { + if (!pkg.getIsFeatureSplits()[splitIdx]) { // Non-feature splits don't have dependencies. continue; } // Implicit dependency on the base. final int targetIdx; - final String splitDependency = pkg.usesSplitNames[splitIdx]; + final String splitDependency = pkg.getUsesSplitNames()[splitIdx]; if (splitDependency != null) { - final int depIdx = Arrays.binarySearch(pkg.splitNames, splitDependency); + final int depIdx = Arrays.binarySearch(pkg.getSplitNames(), splitDependency); if (depIdx < 0) { - throw new IllegalDependencyException("Split '" + pkg.splitNames[splitIdx] + throw new IllegalDependencyException("Split '" + pkg.getSplitNames()[splitIdx] + "' requires split '" + splitDependency + "', which is missing."); } targetIdx = depIdx + 1; @@ -188,26 +197,26 @@ public abstract class SplitDependencyLoader<E extends Exception> { // dependencies and are considered leaves. // // At this point, all splits in splitDependencies have the first element in their array set. - for (int splitIdx = 0; splitIdx < pkg.splitNames.length; splitIdx++) { - if (pkg.isFeatureSplits[splitIdx]) { + for (int splitIdx = 0, size = pkg.getSplitNames().length; splitIdx < size; splitIdx++) { + if (pkg.getIsFeatureSplits()[splitIdx]) { // Feature splits are not configForSplits. continue; } // Implicit feature for the base. final int targetSplitIdx; - final String configForSplit = pkg.configForSplit[splitIdx]; + final String configForSplit = pkg.getConfigForSplit()[splitIdx]; if (configForSplit != null) { - final int depIdx = Arrays.binarySearch(pkg.splitNames, configForSplit); + final int depIdx = Arrays.binarySearch(pkg.getSplitNames(), configForSplit); if (depIdx < 0) { - throw new IllegalDependencyException("Split '" + pkg.splitNames[splitIdx] + throw new IllegalDependencyException("Split '" + pkg.getSplitNames()[splitIdx] + "' targets split '" + configForSplit + "', which is missing."); } - if (!pkg.isFeatureSplits[depIdx]) { - throw new IllegalDependencyException("Split '" + pkg.splitNames[splitIdx] + if (!pkg.getIsFeatureSplits()[depIdx]) { + throw new IllegalDependencyException("Split '" + pkg.getSplitNames()[splitIdx] + "' declares itself as configuration split for a non-feature split '" - + pkg.splitNames[depIdx] + "'"); + + pkg.getSplitNames()[depIdx] + "'"); } targetSplitIdx = depIdx + 1; } else { diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java b/packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java index c6c7142c3bd0..935cb372029d 100755 --- a/packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java +++ b/packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java @@ -25,7 +25,10 @@ import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInstaller; import android.content.pm.PackageManager; -import android.content.pm.PackageParser; +import android.content.pm.parsing.ApkLiteParseUtils; +import android.content.pm.parsing.PackageLite; +import android.content.pm.parsing.result.ParseResult; +import android.content.pm.parsing.result.ParseTypeImpl; import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; @@ -143,16 +146,21 @@ public class InstallInstalling extends AlertActivity { File file = new File(mPackageURI.getPath()); try { - PackageParser.PackageLite pkg = PackageParser.parsePackageLite(file, 0); - params.setAppPackageName(pkg.packageName); - params.setInstallLocation(pkg.installLocation); - params.setSize( - PackageHelper.calculateInstalledSize(pkg, false, params.abiOverride)); - } catch (PackageParser.PackageParserException e) { - Log.e(LOG_TAG, "Cannot parse package " + file + ". Assuming defaults."); - Log.e(LOG_TAG, - "Cannot calculate installed size " + file + ". Try only apk size."); - params.setSize(file.length()); + final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing(); + final ParseResult<PackageLite> result = ApkLiteParseUtils.parsePackageLite( + input.reset(), file, /* flags */ 0); + if (result.isError()) { + Log.e(LOG_TAG, "Cannot parse package " + file + ". Assuming defaults."); + Log.e(LOG_TAG, + "Cannot calculate installed size " + file + ". Try only apk size."); + params.setSize(file.length()); + } else { + final PackageLite pkg = result.getResult(); + params.setAppPackageName(pkg.getPackageName()); + params.setInstallLocation(pkg.getInstallLocation()); + params.setSize( + PackageHelper.calculateInstalledSize(pkg, params.abiOverride)); + } } catch (IOException e) { Log.e(LOG_TAG, "Cannot calculate installed size " + file + ". Try only apk size."); diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java index a12932a88487..de85d9e25642 100644 --- a/services/core/java/com/android/server/pm/ApexManager.java +++ b/services/core/java/com/android/server/pm/ApexManager.java @@ -30,9 +30,9 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageInstaller; import android.content.pm.PackageManager; -import android.content.pm.PackageParser; import android.content.pm.PackageParser.PackageParserException; import android.content.pm.parsing.PackageInfoWithoutStateUtils; +import android.content.pm.parsing.ParsingPackageUtils; import android.os.Binder; import android.os.Environment; import android.os.RemoteException; @@ -508,7 +508,8 @@ public abstract class ApexManager { for (ApexInfo ai : allPkgs) { File apexFile = new File(ai.modulePath); - parallelPackageParser.submit(apexFile, PackageParser.PARSE_COLLECT_CERTIFICATES); + parallelPackageParser.submit(apexFile, + ParsingPackageUtils.PARSE_COLLECT_CERTIFICATES); parsingApexInfo.put(apexFile, ai); } diff --git a/services/core/java/com/android/server/pm/ApkChecksums.java b/services/core/java/com/android/server/pm/ApkChecksums.java index ff3a12ae7355..5373f996d7f8 100644 --- a/services/core/java/com/android/server/pm/ApkChecksums.java +++ b/services/core/java/com/android/server/pm/ApkChecksums.java @@ -24,7 +24,7 @@ import static android.content.pm.Checksum.TYPE_WHOLE_SHA1; import static android.content.pm.Checksum.TYPE_WHOLE_SHA256; import static android.content.pm.Checksum.TYPE_WHOLE_SHA512; import static android.content.pm.PackageManager.EXTRA_CHECKSUMS; -import static android.content.pm.PackageParser.APK_FILE_EXTENSION; +import static android.content.pm.parsing.ApkLiteParseUtils.APK_FILE_EXTENSION; import static android.util.apk.ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA256; import static android.util.apk.ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA512; import static android.util.apk.ApkSigningBlockUtils.CONTENT_DIGEST_VERITY_CHUNKED_SHA256; @@ -39,6 +39,7 @@ import android.content.pm.Checksum; import android.content.pm.PackageManagerInternal; import android.content.pm.PackageParser; import android.content.pm.Signature; +import android.content.pm.parsing.ApkLiteParseUtils; import android.os.Handler; import android.os.SystemClock; import android.os.incremental.IncrementalManager; @@ -171,7 +172,7 @@ public class ApkChecksums { * @throws IllegalArgumentException if the code path is not an .apk. */ public static String buildDigestsPathForApk(String codePath) { - if (!PackageParser.isApkPath(codePath)) { + if (!ApkLiteParseUtils.isApkPath(codePath)) { throw new IllegalStateException("Code path is not an apk " + codePath); } return codePath.substring(0, codePath.length() - APK_FILE_EXTENSION.length()) diff --git a/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java b/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java index 71b99bd4ced2..13fe8a09ce8f 100644 --- a/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java +++ b/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java @@ -17,7 +17,7 @@ package com.android.server.pm; import static android.content.pm.PackageManager.INSTALL_FAILED_INTERNAL_ERROR; -import static android.content.pm.PackageParser.isApkFile; +import static android.content.pm.parsing.ApkLiteParseUtils.isApkFile; import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER; import static android.os.incremental.IncrementalManager.isIncrementalPath; diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index e143bd0cb624..e218dc174ae8 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -81,11 +81,12 @@ import android.content.pm.PackageInstaller.SessionParams; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; import android.content.pm.PackageParser; -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.ApkLite; import android.content.pm.parsing.ApkLiteParseUtils; +import android.content.pm.parsing.PackageLite; +import android.content.pm.parsing.ParsingPackageUtils; import android.content.pm.parsing.result.ParseResult; import android.content.pm.parsing.result.ParseTypeImpl; import android.graphics.Bitmap; @@ -2671,16 +2672,17 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { // Populate package name of the apex session mPackageName = null; - final ApkLite apk; - try { - apk = PackageParser.parseApkLite( - mResolvedBaseFile, PackageParser.PARSE_COLLECT_CERTIFICATES); - } catch (PackageParserException e) { - throw PackageManagerException.from(e); + final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing(); + final ParseResult<ApkLite> ret = ApkLiteParseUtils.parseApkLite(input.reset(), + mResolvedBaseFile, ParsingPackageUtils.PARSE_COLLECT_CERTIFICATES); + if (ret.isError()) { + throw new PackageManagerException(ret.getErrorCode(), ret.getErrorMessage(), + ret.getException()); } + final ApkLite apk = ret.getResult(); if (mPackageName == null) { - mPackageName = apk.packageName; + mPackageName = apk.getPackageName(); mVersionCode = apk.getLongVersionCode(); } } @@ -2745,29 +2747,29 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { // Verify that all staged packages are internally consistent final ArraySet<String> stagedSplits = new ArraySet<>(); - final ArrayMap<String, PackageParser.ApkLite> splitApks = new ArrayMap<>(); - ParseTypeImpl input = ParseTypeImpl.forDefaultParsing(); + final ArrayMap<String, ApkLite> splitApks = new ArrayMap<>(); + final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing(); for (File addedFile : addedFiles) { - ParseResult<ApkLite> result = ApkLiteParseUtils.parseApkLite(input.reset(), - addedFile, PackageParser.PARSE_COLLECT_CERTIFICATES); + final ParseResult<ApkLite> result = ApkLiteParseUtils.parseApkLite(input.reset(), + addedFile, ParsingPackageUtils.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)) { + if (!stagedSplits.add(apk.getSplitName())) { throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, - "Split " + apk.splitName + " was defined multiple times"); + "Split " + apk.getSplitName() + " was defined multiple times"); } // Use first package to define unknown values if (mPackageName == null) { - mPackageName = apk.packageName; + mPackageName = apk.getPackageName(); mVersionCode = apk.getLongVersionCode(); } if (mSigningDetails == PackageParser.SigningDetails.UNKNOWN) { - mSigningDetails = apk.signingDetails; + mSigningDetails = apk.getSigningDetails(); } assertApkConsistentLocked(String.valueOf(addedFile), apk); @@ -2780,10 +2782,10 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } // Yell loudly if installers drop attribute installLocation when apps explicitly set. - if (apk.installLocation != PackageInfo.INSTALL_LOCATION_UNSPECIFIED) { + if (apk.getInstallLocation() != PackageInfo.INSTALL_LOCATION_UNSPECIFIED) { final String installerPackageName = getInstallerPackageName(); if (installerPackageName != null - && (params.installLocation != apk.installLocation)) { + && (params.installLocation != apk.getInstallLocation())) { Slog.wtf(TAG, installerPackageName + " drops manifest attribute android:installLocation in " + targetName + " for " + mPackageName); @@ -2791,14 +2793,14 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } final File targetFile = new File(stageDir, targetName); - resolveAndStageFileLocked(addedFile, targetFile, apk.splitName); + resolveAndStageFileLocked(addedFile, targetFile, apk.getSplitName()); // Base is coming from session - if (apk.splitName == null) { + if (apk.getSplitName() == null) { mResolvedBaseFile = targetFile; baseApk = apk; } else { - splitApks.put(apk.splitName, apk); + splitApks.put(apk.getSplitName(), apk); } } @@ -2854,7 +2856,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "Full install must include a base package"); } - if (baseApk.isSplitRequired && stagedSplits.size() <= 1) { + if (baseApk.isSplitRequired() && stagedSplits.size() <= 1) { throw new PackageManagerException(INSTALL_FAILED_MISSING_SPLIT, "Missing split for " + mPackageName); } @@ -2879,10 +2881,10 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } final PackageLite existing = pkgLiteResult.getResult(); packageLite = existing; - assertPackageConsistentLocked("Existing", existing.packageName, + assertPackageConsistentLocked("Existing", existing.getPackageName(), existing.getLongVersionCode()); final PackageParser.SigningDetails signingDetails = - unsafeGetCertsWithoutVerification(existing.baseCodePath); + unsafeGetCertsWithoutVerification(existing.getBaseApkPath()); if (!mSigningDetails.signaturesMatchExactly(signingDetails)) { throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "Existing signatures are inconsistent"); @@ -2895,10 +2897,10 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } // Inherit splits if not overridden. - if (!ArrayUtils.isEmpty(existing.splitNames)) { - for (int i = 0; i < existing.splitNames.length; i++) { - final String splitName = existing.splitNames[i]; - final File splitFile = new File(existing.splitCodePaths[i]); + if (!ArrayUtils.isEmpty(existing.getSplitNames())) { + for (int i = 0; i < existing.getSplitNames().length; i++) { + final String splitName = existing.getSplitNames()[i]; + final File splitFile = new File(existing.getSplitApkPaths()[i]); final boolean splitRemoved = removeSplitList.contains(splitName); if (!stagedSplits.contains(splitName) && !splitRemoved) { inheritFileLocked(splitFile); @@ -2978,8 +2980,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } } // For the case of split required, failed if no splits existed - if (packageLite.isSplitRequired) { - final int existingSplits = ArrayUtils.size(existing.splitNames); + if (packageLite.isSplitRequired()) { + final int existingSplits = ArrayUtils.size(existing.getSplitNames()); final boolean allSplitsRemoved = (existingSplits == removeSplitList.size()); final boolean onlyBaseFileStaged = (stagedSplits.size() == 1 && stagedSplits.contains(null)); @@ -2989,7 +2991,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } } } - if (packageLite.useEmbeddedDex) { + if (packageLite.isUseEmbeddedDex()) { for (File file : mResolvedStagedFiles) { if (file.getName().endsWith(".apk") && !DexManager.auditUncompressedDexInApk(file.getPath())) { @@ -3002,7 +3004,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { final boolean isInstallerShell = (mInstallerUid == Process.SHELL_UID); if (isInstallerShell && isIncrementalInstallation() && mIncrementalFileStorages != null) { - if (!packageLite.debuggable && !packageLite.profilableByShell) { + if (!packageLite.isDebuggable() && !packageLite.isProfileableByShell()) { mIncrementalFileStorages.disallowReadLogs(); } } @@ -3174,8 +3176,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { @GuardedBy("mLock") private void assertApkConsistentLocked(String tag, ApkLite apk) throws PackageManagerException { - assertPackageConsistentLocked(tag, apk.packageName, apk.getLongVersionCode()); - if (!mSigningDetails.signaturesMatchExactly(apk.signingDetails)) { + assertPackageConsistentLocked(tag, apk.getPackageName(), apk.getLongVersionCode()); + if (!mSigningDetails.signaturesMatchExactly(apk.getSigningDetails())) { throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag + " signatures are inconsistent"); } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 68b06989b24e..50aacd677fdc 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -101,7 +101,7 @@ import static android.content.pm.PackageManager.TYPE_UNKNOWN; import static android.content.pm.PackageManager.UNINSTALL_REASON_UNKNOWN; import static android.content.pm.PackageManagerInternal.LAST_KNOWN_PACKAGE; import static android.content.pm.PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V4; -import static android.content.pm.PackageParser.isApkFile; +import static android.content.pm.parsing.ApkLiteParseUtils.isApkFile; import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER; import static android.os.incremental.IncrementalManager.isIncrementalPath; import static android.os.storage.StorageManager.FLAG_STORAGE_CE; @@ -211,9 +211,7 @@ import android.content.pm.PackageManagerInternal; import android.content.pm.PackageManagerInternal.PackageListObserver; import android.content.pm.PackageManagerInternal.PrivateResolveFlags; import android.content.pm.PackageParser; -import android.content.pm.PackageParser.PackageLite; import android.content.pm.PackageParser.PackageParserException; -import android.content.pm.PackageParser.ParseFlags; import android.content.pm.PackageParser.SigningDetails; import android.content.pm.PackageParser.SigningDetails.SignatureSchemeVersion; import android.content.pm.PackagePartitions; @@ -241,7 +239,9 @@ 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.PackageLite; import android.content.pm.parsing.ParsingPackageUtils; +import android.content.pm.parsing.ParsingPackageUtils.ParseFlags; import android.content.pm.parsing.component.ParsedActivity; import android.content.pm.parsing.component.ParsedInstrumentation; import android.content.pm.parsing.component.ParsedIntentInfo; @@ -6251,7 +6251,7 @@ public class PackageManagerService extends IPackageManager.Stub if (separateProcesses != null && separateProcesses.length() > 0) { if ("*".equals(separateProcesses)) { - mDefParseFlags = PackageParser.PARSE_IGNORE_PROCESSES; + mDefParseFlags = ParsingPackageUtils.PARSE_IGNORE_PROCESSES; mSeparateProcesses = null; Slog.w(TAG, "Running with debug.separate_processes: * (ALL)"); } else { @@ -6451,7 +6451,7 @@ public class PackageManagerService extends IPackageManager.Stub scanFlags = scanFlags | SCAN_FIRST_BOOT_OR_UPGRADE; } - final int systemParseFlags = mDefParseFlags | PackageParser.PARSE_IS_SYSTEM_DIR; + final int systemParseFlags = mDefParseFlags | ParsingPackageUtils.PARSE_IS_SYSTEM_DIR; final int systemScanFlags = scanFlags | SCAN_AS_SYSTEM; PackageParser2 packageParser = injector.getScanningCachingPackageParser(); @@ -7091,7 +7091,7 @@ public class PackageManagerService extends IPackageManager.Stub */ private boolean enableCompressedPackage(AndroidPackage stubPkg, @NonNull PackageSetting stubPkgSetting) { - final int parseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY + final int parseFlags = mDefParseFlags | ParsingPackageUtils.PARSE_CHATTY | PackageParser.PARSE_ENFORCE_CODE; synchronized (mInstallLock) { final AndroidPackage pkg; @@ -11317,7 +11317,8 @@ public class PackageManagerService extends IPackageManager.Stub @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime, @Nullable UserHandle user) throws PackageManagerException { - final boolean scanSystemPartition = (parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0; + final boolean scanSystemPartition = + (parseFlags & ParsingPackageUtils.PARSE_IS_SYSTEM_DIR) != 0; final String renamedPkgName; final PackageSetting disabledPkgSetting; final boolean isSystemPkgUpdated; @@ -11360,7 +11361,7 @@ public class PackageManagerService extends IPackageManager.Stub 0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/, true) : null; if (DEBUG_PACKAGE_SCANNING - && (parseFlags & PackageParser.PARSE_CHATTY) != 0 + && (parseFlags & ParsingPackageUtils.PARSE_CHATTY) != 0 && sharedUserSetting != null) { Log.d(TAG, "Shared UserID " + parsedPackage.getSharedUserId() + " (uid=" + sharedUserSetting.userId + "):" @@ -13179,10 +13180,11 @@ public class PackageManagerService extends IPackageManager.Stub sharedUserSetting = mSettings.getSharedUserLPw(parsedPackage.getSharedUserId(), 0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/, true /*create*/); if (DEBUG_PACKAGE_SCANNING) { - if ((parseFlags & PackageParser.PARSE_CHATTY) != 0) + if ((parseFlags & ParsingPackageUtils.PARSE_CHATTY) != 0) { Log.d(TAG, "Shared UserID " + parsedPackage.getSharedUserId() + " (uid=" + sharedUserSetting.userId + "):" + " packages=" + sharedUserSetting.packages); + } } } String platformPackageName = mPlatformPackage == null @@ -13339,7 +13341,7 @@ public class PackageManagerService extends IPackageManager.Stub final int userId = user == null ? 0 : user.getIdentifier(); // Modify state for the given package setting commitPackageSettings(pkg, oldPkg, pkgSetting, scanFlags, - (parseFlags & PackageParser.PARSE_CHATTY) != 0 /*chatty*/, reconciledPkg); + (parseFlags & ParsingPackageUtils.PARSE_CHATTY) != 0 /*chatty*/, reconciledPkg); if (pkgSetting.getInstantApp(userId)) { mInstantAppRegistry.addInstantAppLPw(userId, pkgSetting.appId); } @@ -13548,8 +13550,9 @@ public class PackageManagerService extends IPackageManager.Stub List<String> changedAbiCodePath = null; if (DEBUG_PACKAGE_SCANNING) { - if ((parseFlags & PackageParser.PARSE_CHATTY) != 0) + if ((parseFlags & ParsingPackageUtils.PARSE_CHATTY) != 0) { Log.d(TAG, "Scanning package " + parsedPackage.getPackageName()); + } } // Initialize package source and resource directories @@ -13816,7 +13819,7 @@ public class PackageManagerService extends IPackageManager.Stub } else if (pkgSetting.firstInstallTime == 0) { // We need *something*. Take time time stamp of the file. pkgSetting.firstInstallTime = pkgSetting.lastUpdateTime = scanFileTime; - } else if ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0) { + } else if ((parseFlags & ParsingPackageUtils.PARSE_IS_SYSTEM_DIR) != 0) { if (scanFileTime != pkgSetting.timeStamp) { // A package on the system image has changed; consider this // to be an update. @@ -14013,7 +14016,7 @@ public class PackageManagerService extends IPackageManager.Stub private void assertPackageIsValid(AndroidPackage pkg, final @ParseFlags int parseFlags, final @ScanFlags int scanFlags) throws PackageManagerException { - if ((parseFlags & PackageParser.PARSE_ENFORCE_CODE) != 0) { + if ((parseFlags & ParsingPackageUtils.PARSE_ENFORCE_CODE) != 0) { assertCodePolicy(pkg); } @@ -14270,7 +14273,7 @@ public class PackageManagerService extends IPackageManager.Stub if ((scanFlags & SCAN_AS_SYSTEM) != 0) { // We are scanning a system overlay. This can be the first scan of the // system/vendor/oem partition, or an update to the system overlay. - if ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) { + if ((parseFlags & ParsingPackageUtils.PARSE_IS_SYSTEM_DIR) == 0) { // This must be an update to a system overlay. Immutable overlays cannot be // upgraded. Objects.requireNonNull(mOverlayConfig, @@ -14350,7 +14353,7 @@ public class PackageManagerService extends IPackageManager.Stub // If the package is not on a system partition ensure it is signed with at least the // minimum signature scheme version required for its target SDK. - if ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) { + if ((parseFlags & ParsingPackageUtils.PARSE_IS_SYSTEM_DIR) == 0) { int minSignatureSchemeVersion = ApkSignatureVerifier.getMinimumSignatureSchemeVersionForTargetSdk( pkg.getTargetSdkVersion()); @@ -18015,11 +18018,12 @@ public class PackageManagerService extends IPackageManager.Stub // Try enumerating all code paths before deleting List<String> allCodePaths = Collections.EMPTY_LIST; if (codeFile != null && codeFile.exists()) { - try { - final PackageLite pkg = PackageParser.parsePackageLite(codeFile, 0); - allCodePaths = pkg.getAllCodePaths(); - } catch (PackageParserException e) { - // Ignored; we tried our best + final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing(); + final ParseResult<PackageLite> result = ApkLiteParseUtils.parsePackageLite( + input.reset(), codeFile, /* flags */ 0); + if (result.isSuccess()) { + // Ignore error; we tried our best + allCodePaths = result.getResult().getAllApkPaths(); } } @@ -18637,7 +18641,7 @@ public class PackageManagerService extends IPackageManager.Stub // We just determined the app is signed correctly, so bring // over the latest parsed certs. } else { - if ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) { + if ((parseFlags & ParsingPackageUtils.PARSE_IS_SYSTEM_DIR) == 0) { throw new ReconcileFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package " + parsedPackage.getPackageName() + " upgrade keys do not match the previously installed" @@ -18687,7 +18691,7 @@ public class PackageManagerService extends IPackageManager.Stub } } } catch (PackageManagerException e) { - if ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) { + if ((parseFlags & ParsingPackageUtils.PARSE_IS_SYSTEM_DIR) == 0) { throw new ReconcileFailure(e); } signingDetails = parsedPackage.getSigningDetails(); @@ -18766,7 +18770,8 @@ public class PackageManagerService extends IPackageManager.Stub // apps are scanned to avoid dependency based scanning. final ScanResult scanResult = scannedPackages.get(installPackageName); if ((scanResult.request.scanFlags & SCAN_BOOTING) != 0 - || (scanResult.request.parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0) { + || (scanResult.request.parseFlags & ParsingPackageUtils.PARSE_IS_SYSTEM_DIR) + != 0) { continue; } try { @@ -19652,9 +19657,9 @@ public class PackageManagerService extends IPackageManager.Stub } // Retrieve PackageSettings and parse package - @ParseFlags final int parseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY - | PackageParser.PARSE_ENFORCE_CODE - | (onExternal ? PackageParser.PARSE_EXTERNAL_STORAGE : 0); + @ParseFlags final int parseFlags = mDefParseFlags | ParsingPackageUtils.PARSE_CHATTY + | ParsingPackageUtils.PARSE_ENFORCE_CODE + | (onExternal ? ParsingPackageUtils.PARSE_EXTERNAL_STORAGE : 0); Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage"); final ParsedPackage parsedPackage; @@ -21384,8 +21389,8 @@ public class PackageManagerService extends IPackageManager.Stub final File codePath = new File(codePathString); @ParseFlags int parseFlags = mDefParseFlags - | PackageParser.PARSE_MUST_BE_APK - | PackageParser.PARSE_IS_SYSTEM_DIR; + | ParsingPackageUtils.PARSE_MUST_BE_APK + | ParsingPackageUtils.PARSE_IS_SYSTEM_DIR; @ScanFlags int scanFlags = SCAN_AS_SYSTEM; for (int i = mDirsToScanAsSystem.size() - 1; i >= 0; i--) { ScanPartition partition = mDirsToScanAsSystem.get(i); @@ -24837,7 +24842,7 @@ public class PackageManagerService extends IPackageManager.Stub final ArrayList<PackageFreezer> freezers = new ArrayList<>(); final ArrayList<AndroidPackage> loaded = new ArrayList<>(); - final int parseFlags = mDefParseFlags | PackageParser.PARSE_EXTERNAL_STORAGE; + final int parseFlags = mDefParseFlags | ParsingPackageUtils.PARSE_EXTERNAL_STORAGE; final VersionInfo ver; final List<PackageSetting> packages; diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java index d3d7c6055fce..ee94b8599625 100644 --- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java +++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java @@ -35,9 +35,12 @@ import android.content.Intent; import android.content.pm.PackageInfoLite; import android.content.pm.PackageManager; import android.content.pm.PackageParser; -import android.content.pm.PackageParser.PackageParserException; import android.content.pm.ResolveInfo; import android.content.pm.Signature; +import android.content.pm.parsing.ApkLiteParseUtils; +import android.content.pm.parsing.PackageLite; +import android.content.pm.parsing.result.ParseResult; +import android.content.pm.parsing.result.ParseTypeImpl; import android.os.Build; import android.os.Debug; import android.os.Environment; @@ -819,8 +822,8 @@ public class PackageManagerServiceUtils { /** * Parse given package and return minimal details. */ - public static PackageInfoLite getMinimalPackageInfo(Context context, - PackageParser.PackageLite pkg, String packagePath, int flags, String abiOverride) { + public static PackageInfoLite getMinimalPackageInfo(Context context, PackageLite pkg, + String packagePath, int flags, String abiOverride) { final PackageInfoLite ret = new PackageInfoLite(); if (packagePath == null || pkg == null) { Slog.i(TAG, "Invalid package file " + packagePath); @@ -843,19 +846,19 @@ public class PackageManagerServiceUtils { } final int recommendedInstallLocation = PackageHelper.resolveInstallLocation(context, - pkg.packageName, pkg.installLocation, sizeBytes, flags); - - ret.packageName = pkg.packageName; - ret.splitNames = pkg.splitNames; - ret.versionCode = pkg.versionCode; - ret.versionCodeMajor = pkg.versionCodeMajor; - ret.baseRevisionCode = pkg.baseRevisionCode; - ret.splitRevisionCodes = pkg.splitRevisionCodes; - ret.installLocation = pkg.installLocation; - ret.verifiers = pkg.verifiers; + pkg.getPackageName(), pkg.getInstallLocation(), sizeBytes, flags); + + ret.packageName = pkg.getPackageName(); + ret.splitNames = pkg.getSplitNames(); + ret.versionCode = pkg.getVersionCode(); + ret.versionCodeMajor = pkg.getVersionCodeMajor(); + ret.baseRevisionCode = pkg.getBaseRevisionCode(); + ret.splitRevisionCodes = pkg.getSplitRevisionCodes(); + ret.installLocation = pkg.getInstallLocation(); + ret.verifiers = pkg.getVerifiers(); ret.recommendedInstallLocation = recommendedInstallLocation; - ret.multiArch = pkg.multiArch; - ret.debuggable = pkg.debuggable; + ret.multiArch = pkg.isMultiArch(); + ret.debuggable = pkg.isDebuggable(); return ret; } @@ -868,11 +871,16 @@ public class PackageManagerServiceUtils { */ public static long calculateInstalledSize(String packagePath, String abiOverride) { final File packageFile = new File(packagePath); - final PackageParser.PackageLite pkg; try { - pkg = PackageParser.parsePackageLite(packageFile, 0); - return PackageHelper.calculateInstalledSize(pkg, abiOverride); - } catch (PackageParserException | IOException e) { + final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing(); + final ParseResult<PackageLite> result = ApkLiteParseUtils.parsePackageLite( + input.reset(), packageFile, /* flags */ 0); + if (result.isError()) { + throw new PackageManagerException(result.getErrorCode(), + result.getErrorMessage(), result.getException()); + } + return PackageHelper.calculateInstalledSize(result.getResult(), abiOverride); + } catch (PackageManagerException | IOException e) { Slog.w(TAG, "Failed to calculate installed size: " + e); return -1; } @@ -931,16 +939,23 @@ public class PackageManagerServiceUtils { try { final File packageFile = new File(packagePath); - final PackageParser.PackageLite pkg = PackageParser.parsePackageLite(packageFile, 0); - copyFile(pkg.baseCodePath, targetDir, "base.apk"); - if (!ArrayUtils.isEmpty(pkg.splitNames)) { - for (int i = 0; i < pkg.splitNames.length; i++) { - copyFile(pkg.splitCodePaths[i], targetDir, - "split_" + pkg.splitNames[i] + ".apk"); + final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing(); + final ParseResult<PackageLite> result = ApkLiteParseUtils.parsePackageLite( + input.reset(), packageFile, /* flags */ 0); + if (result.isError()) { + Slog.w(TAG, "Failed to parse package at " + packagePath); + return result.getErrorCode(); + } + final PackageLite pkg = result.getResult(); + copyFile(pkg.getBaseApkPath(), targetDir, "base.apk"); + if (!ArrayUtils.isEmpty(pkg.getSplitNames())) { + for (int i = 0; i < pkg.getSplitNames().length; i++) { + copyFile(pkg.getSplitApkPaths()[i], targetDir, + "split_" + pkg.getSplitNames()[i] + ".apk"); } } return PackageManager.INSTALL_SUCCEEDED; - } catch (PackageParserException | IOException | ErrnoException e) { + } catch (IOException | ErrnoException e) { Slog.w(TAG, "Failed to copy package at " + packagePath + ": " + e); return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; } diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java index 446342a8f512..3207d56a820e 100644 --- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java +++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java @@ -49,8 +49,6 @@ import android.content.pm.PackageItemInfo; import android.content.pm.PackageManager; 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.ParceledListSlice; import android.content.pm.PermissionGroupInfo; import android.content.pm.PermissionInfo; @@ -61,7 +59,9 @@ import android.content.pm.VersionedPackage; import android.content.pm.dex.ArtManager; import android.content.pm.dex.DexMetadataHelper; import android.content.pm.dex.ISnapshotRuntimeProfileCallback; +import android.content.pm.parsing.ApkLite; import android.content.pm.parsing.ApkLiteParseUtils; +import android.content.pm.parsing.PackageLite; import android.content.pm.parsing.result.ParseResult; import android.content.pm.parsing.result.ParseTypeImpl; import android.content.res.AssetManager; @@ -555,8 +555,8 @@ class PackageManagerShellCommand extends ShellCommand { apkLiteResult.getException()); } final ApkLite apkLite = apkLiteResult.getResult(); - PackageLite pkgLite = new PackageLite(null, apkLite.codePath, apkLite, null, null, - null, null, null, null); + final PackageLite pkgLite = new PackageLite(null, apkLite.getPath(), apkLite, null, + null, null, null, null, null); sessionSize += PackageHelper.calculateInstalledSize(pkgLite, params.sessionParams.abiOverride, fd.getFileDescriptor()); } catch (IOException e) { diff --git a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackage.java b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackage.java index a13680ad32af..471a4d3ada46 100644 --- a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackage.java +++ b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackage.java @@ -24,6 +24,7 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageParser; import android.content.pm.PermissionGroupInfo; import android.content.pm.parsing.ParsingPackageRead; +import android.content.pm.parsing.ParsingPackageUtils; import android.content.pm.parsing.component.ParsedAttribution; import android.content.pm.parsing.component.ParsedIntentInfo; import android.content.pm.parsing.component.ParsedPermissionGroup; @@ -56,7 +57,7 @@ public interface AndroidPackage extends PkgAppInfo, PkgPackageInfo, ParsingPacka /** * The names of packages to adopt ownership of permissions from, parsed under - * {@link PackageParser#TAG_ADOPT_PERMISSIONS}. + * {@link ParsingPackageUtils#TAG_ADOPT_PERMISSIONS}. * @see R.styleable#AndroidManifestOriginalPackage_name */ @NonNull @@ -84,7 +85,7 @@ public interface AndroidPackage extends PkgAppInfo, PkgPackageInfo, ParsingPacka /** * For use with {@link com.android.server.pm.KeySetManagerService}. Parsed in - * {@link PackageParser#TAG_KEY_SETS}. + * {@link ParsingPackageUtils#TAG_KEY_SETS}. * @see R.styleable#AndroidManifestKeySet * @see R.styleable#AndroidManifestPublicKey */ @@ -230,7 +231,7 @@ public interface AndroidPackage extends PkgAppInfo, PkgPackageInfo, ParsingPacka /** * For use with {@link com.android.server.pm.KeySetManagerService}. Parsed in - * {@link PackageParser#TAG_KEY_SETS}. + * {@link ParsingPackageUtils#TAG_KEY_SETS}. * @see R.styleable#AndroidManifestUpgradeKeySet */ @NonNull diff --git a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java index ab25a7c772c0..37dfea4ee0f3 100644 --- a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java +++ b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java @@ -21,12 +21,12 @@ import android.annotation.Nullable; 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.pm.SharedLibraryInfo; import android.content.pm.VersionedPackage; import android.content.pm.dex.DexMetadataHelper; import android.content.pm.parsing.ParsingPackageRead; +import android.content.pm.parsing.ParsingPackageUtils; import android.content.pm.parsing.component.ParsedActivity; import android.content.pm.parsing.component.ParsedInstrumentation; import android.content.pm.parsing.component.ParsedProvider; @@ -233,7 +233,7 @@ public class AndroidPackageUtils { } public static int getIcon(ParsingPackageRead pkg) { - return (PackageParser.sUseRoundIcon && pkg.getRoundIconRes() != 0) + return (ParsingPackageUtils.sUseRoundIcon && pkg.getRoundIconRes() != 0) ? pkg.getRoundIconRes() : pkg.getIconRes(); } 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 eaf62cbb8201..0dcd608e6bbd 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 @@ -23,12 +23,11 @@ import static org.junit.Assert.fail; import android.content.Context; import android.content.pm.PackageManager; -import android.content.pm.PackageParser; -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.ApkLite; import android.content.pm.parsing.ApkLiteParseUtils; +import android.content.pm.parsing.PackageLite; import android.content.pm.parsing.result.ParseResult; import android.content.pm.parsing.result.ParseTypeImpl; import android.os.FileUtils; @@ -38,6 +37,7 @@ import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import com.android.frameworks.servicestests.R; +import com.android.server.pm.PackageManagerException; import com.android.server.pm.parsing.TestPackageParser2; import com.android.server.pm.parsing.pkg.AndroidPackageUtils; import com.android.server.pm.parsing.pkg.ParsedPackage; @@ -207,28 +207,35 @@ public class DexMetadataHelperTest { } @Test - public void testPackageSizeWithDmFile() - throws IOException, PackageParserException { + public void testPackageSizeWithDmFile() throws IOException { copyApkToToTmpDir("install_split_base.apk", R.raw.install_split_base); - File dm = createDexMetadataFile("install_split_base.apk"); - ParseResult<PackageLite> result = ApkLiteParseUtils.parsePackageLite( + final File dm = createDexMetadataFile("install_split_base.apk"); + final 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(); + final PackageLite pkg = result.getResult(); Assert.assertEquals(dm.length(), DexMetadataHelper.getPackageDexMetadataSize(pkg)); } // This simulates the 'adb shell pm install' flow. @Test - public void testPackageSizeWithPartialPackageLite() throws IOException, PackageParserException { - File base = copyApkToToTmpDir("install_split_base", R.raw.install_split_base); - File dm = createDexMetadataFile("install_split_base.apk"); + public void testPackageSizeWithPartialPackageLite() throws IOException, + PackageManagerException { + final File base = copyApkToToTmpDir("install_split_base", R.raw.install_split_base); + final File dm = createDexMetadataFile("install_split_base.apk"); try (FileInputStream is = new FileInputStream(base)) { - ApkLite baseApk = PackageParser.parseApkLite(is.getFD(), base.getAbsolutePath(), 0); - PackageLite pkgLite = new PackageLite(null, baseApk.codePath, baseApk, null, null, null, - null, null, null); + final ParseResult<ApkLite> result = ApkLiteParseUtils.parseApkLite( + ParseTypeImpl.forDefaultParsing().reset(), is.getFD(), + base.getAbsolutePath(), /* flags */ 0); + if (result.isError()) { + throw new PackageManagerException(result.getErrorCode(), + result.getErrorMessage(), result.getException()); + } + final ApkLite baseApk = result.getResult(); + final PackageLite pkgLite = new PackageLite(null, baseApk.getPath(), baseApk, null, + null, null, null, null, null); Assert.assertEquals(dm.length(), DexMetadataHelper.getPackageDexMetadataSize(pkgLite)); } |