Merge "Refactor PackageParser (2/n)" into sc-dev
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 45f072a..fe8bf9d 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.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.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.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.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 @@
             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 982fce9..bf35c4d 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 @@
      * 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 @@
      * @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 @@
      * 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 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 51b81b6..a3c2cbc 100644
--- a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
+++ b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
@@ -66,6 +66,8 @@
     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 @@
      *
      * @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 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 @@
         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 @@
             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 @@
      * @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 @@
      * @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 @@
             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 @@
      * @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 @@
      *
      * @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 @@
      * @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 @@
                         "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 @@
         }
     }
 
-    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 @@
                 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 @@
                         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 @@
                         }
                     }
                 }
-            } 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 @@
                         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 @@
                     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 @@
         }
 
         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 @@
             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 @@
             }
         }
     }
+
+    /**
+     * 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 f8fd4a5..b7365b3 100644
--- a/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
+++ b/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
@@ -385,7 +385,7 @@
         }
 
         // 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 38d3940..51ec297 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageImpl.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageImpl.java
@@ -335,7 +335,7 @@
 
     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 @@
         // 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 13ae7a2..a102e82 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageRead.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageRead.java
@@ -66,7 +66,7 @@
 
     /**
      * 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 @@
 
     /**
      * 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 @@
 
     /**
      * 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 494b3cc..b054304 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageUtils.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
@@ -189,6 +189,12 @@
             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 @@
      */
     @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 @@
      */
     @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 @@
      */
     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 @@
         // 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 @@
 
         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 @@
                 }
             }
 
-            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 @@
      */
     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 @@
             }
 
             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 @@
         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 @@
         }
 
         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 @@
 
             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 @@
             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 @@
                     "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 @@
 
             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 @@
                     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 @@
                 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 @@
                 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 @@
                     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 @@
             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 @@
             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 @@
             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 @@
             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 @@
             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 @@
             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 @@
     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 @@
                 }
 
                 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 @@
                 }
 
                 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 @@
 
     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 @@
                         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 @@
                     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 @@
 
                     pkg.setFullBackupContent(fullBackupContent);
                 }
-                if (PackageParser.DEBUG_BACKUP) {
+                if (DEBUG_BACKUP) {
                     Slog.v(TAG, "fullBackupContent=" + fullBackupContent + " for " + pkgName);
                 }
             }
@@ -1994,7 +2000,7 @@
                 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 @@
                 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 @@
                 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 @@
                     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 @@
     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 @@
             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 @@
             // 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 @@
     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 @@
             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 @@
             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 @@
                     } 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 d65f8ff..0403a25 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.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 @@
     @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 1915028..2ea24f7 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.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 @@
         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 f96bd54..f821e08 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.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 @@
         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 @@
                 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 @@
                     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 @@
                                     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 @@
             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 @@
         }
 
         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 @@
         }
         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 368dcfd..939e77f 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.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 @@
                 }
             }
 
-            if (PackageParser.sUseRoundIcon) {
+            if (ParsingPackageUtils.sUseRoundIcon) {
                 intentInfo.icon = sa.getResourceId(
                         R.styleable.AndroidManifestIntentFilter_roundIcon, 0);
             }
@@ -141,7 +142,7 @@
 
         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 9e3a8f4..f3caf60 100644
--- a/core/java/android/content/pm/split/DefaultSplitAssetLoader.java
+++ b/core/java/android/content/pm/split/DefaultSplitAssetLoader.java
@@ -18,9 +18,11 @@
 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 @@
  * @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 @@
             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 58eaabf..523ca40 100644
--- a/core/java/android/content/pm/split/SplitAssetDependencyLoader.java
+++ b/core/java/android/content/pm/split/SplitAssetDependencyLoader.java
@@ -19,9 +19,11 @@
 
 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 @@
     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 @@
 
     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 3586546..3e68132 100644
--- a/core/java/android/content/pm/split/SplitDependencyLoader.java
+++ b/core/java/android/content/pm/split/SplitDependencyLoader.java
@@ -17,7 +17,7 @@
 
 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 @@
         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 @@
 
         // 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 @@
         // 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 c6c7142..935cb37 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.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 @@
 
                 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 a12932a8..de85d9e 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.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 @@
 
             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 ff3a12a..5373f99 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_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.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 @@
      * @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 71b99bd..13fe8a0 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 e143bd0..e218dc1 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.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 @@
 
         // 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 @@
 
         // 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 @@
             }
 
             // 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 @@
             }
 
             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 @@
                 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 @@
             }
             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 @@
             }
 
             // 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 @@
                 }
             }
             // 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 @@
                 }
             }
         }
-        if (packageLite.useEmbeddedDex) {
+        if (packageLite.isUseEmbeddedDex()) {
             for (File file : mResolvedStagedFiles) {
                 if (file.getName().endsWith(".apk")
                         && !DexManager.auditUncompressedDexInApk(file.getPath())) {
@@ -3002,7 +3004,7 @@
 
         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 @@
     @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 68b0698..50aacd6 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.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.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.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 @@
 
         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 @@
                 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 @@
      */
     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 @@
             @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 @@
                             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 @@
                 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 @@
         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 @@
         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 @@
         } 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 @@
     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 @@
                 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 @@
 
             // 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 @@
             // 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 @@
                     // 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 @@
                         }
                     }
                 } 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 @@
             // 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 @@
         }
 
         // 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 @@
         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 @@
 
         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 d3d7c60..ee94b85 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.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 @@
     /**
      * 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 @@
         }
 
         final int recommendedInstallLocation = PackageHelper.resolveInstallLocation(context,
-                pkg.packageName, pkg.installLocation, sizeBytes, flags);
+                pkg.getPackageName(), pkg.getInstallLocation(), 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;
+        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 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 @@
 
         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 446342a..3207d56a 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.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.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 @@
                             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 a13680a..471a4d3 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.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 @@
 
     /**
      * 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 @@
 
     /**
      * 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 @@
 
     /**
      * 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 ab25a7c..37dfea4 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.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 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 eaf62cb..0dcd608 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 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.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 @@
     }
 
     @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));
         }