Revert "Revert "Deprecate PackageParser#Package""

This reverts commit 8e18a0ab8980a3092d6c7e1d2edc6407655af609.

Exempt-From-Owner-Approval: Revert to re-add approved change

Change-Id: I5b5195470f365a2347cbf444cc0494d119e42ffc
diff --git a/Android.bp b/Android.bp
index 9426a9c..661b1cc 100644
--- a/Android.bp
+++ b/Android.bp
@@ -372,7 +372,7 @@
 
     exclude_srcs: [
         // See comment on framework-atb-backward-compatibility module below
-        "core/java/android/content/pm/AndroidTestBaseUpdater.java",
+        "core/java/android/content/pm/parsing/library/AndroidTestBaseUpdater.java",
     ],
 
     sdk_version: "core_platform",
@@ -536,7 +536,7 @@
     installable: true,
     libs: ["app-compat-annotations"],
     srcs: [
-        "core/java/android/content/pm/AndroidTestBaseUpdater.java",
+        "core/java/android/content/pm/parsing/library/AndroidTestBaseUpdater.java",
     ],
 }
 
diff --git a/config/preloaded-classes b/config/preloaded-classes
index 0394a7a..97f009c 100644
--- a/config/preloaded-classes
+++ b/config/preloaded-classes
@@ -878,7 +878,7 @@
 android.content.pm.ActivityInfo$1
 android.content.pm.ActivityInfo$WindowLayout
 android.content.pm.ActivityInfo
-android.content.pm.AndroidHidlUpdater
+android.content.pm.parsing.library.AndroidHidlUpdater
 android.content.pm.ApplicationInfo$1
 android.content.pm.ApplicationInfo
 android.content.pm.BaseParceledListSlice
@@ -922,10 +922,10 @@
 android.content.pm.LauncherApps
 android.content.pm.ModuleInfo$1
 android.content.pm.ModuleInfo
-android.content.pm.OrgApacheHttpLegacyUpdater
-android.content.pm.PackageBackwardCompatibility$AndroidTestRunnerSplitUpdater
-android.content.pm.PackageBackwardCompatibility$RemoveUnnecessaryAndroidTestBaseLibrary
-android.content.pm.PackageBackwardCompatibility
+android.content.pm.parsing.library.OrgApacheHttpLegacyUpdater
+android.content.pm.parsing.library.PackageBackwardCompatibility$AndroidTestRunnerSplitUpdater
+android.content.pm.parsing.library.PackageBackwardCompatibility$RemoveUnnecessaryAndroidTestBaseLibrary
+android.content.pm.parsing.library.PackageBackwardCompatibility
 android.content.pm.PackageInfo$1
 android.content.pm.PackageInfo
 android.content.pm.PackageInstaller$Session
@@ -960,7 +960,7 @@
 android.content.pm.PackageParser$SigningDetails
 android.content.pm.PackageParser$SplitNameComparator
 android.content.pm.PackageParser
-android.content.pm.PackageSharedLibraryUpdater
+android.content.pm.parsing.library.PackageSharedLibraryUpdater
 android.content.pm.PackageStats$1
 android.content.pm.PackageStats
 android.content.pm.PackageUserState
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index e724443..26193f6 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -1376,7 +1376,8 @@
             this.minHeight = minHeight;
         }
 
-        WindowLayout(Parcel source) {
+        /** @hide */
+        public WindowLayout(Parcel source) {
             width = source.readInt();
             widthFraction = source.readFloat();
             height = source.readInt();
diff --git a/core/java/android/content/pm/AndroidHidlUpdater.java b/core/java/android/content/pm/AndroidHidlUpdater.java
deleted file mode 100644
index d0657e5..0000000
--- a/core/java/android/content/pm/AndroidHidlUpdater.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.content.pm;
-
-import static android.content.pm.SharedLibraryNames.ANDROID_HIDL_BASE;
-import static android.content.pm.SharedLibraryNames.ANDROID_HIDL_MANAGER;
-
-import android.content.pm.PackageParser.Package;
-import android.os.Build;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-/**
- * Updates a package to ensure that if it targets <= P that the android.hidl.base-V1.0-java
- * and android.hidl.manager-V1.0-java libraries are included by default.
- *
- * @hide
- */
-@VisibleForTesting
-public class AndroidHidlUpdater extends PackageSharedLibraryUpdater {
-
-    @Override
-    public void updatePackage(Package pkg) {
-        ApplicationInfo info = pkg.applicationInfo;
-
-        // This was the default <= P and is maintained for backwards compatibility.
-        boolean isLegacy = info.targetSdkVersion <= Build.VERSION_CODES.P;
-        // Only system apps use these libraries
-        boolean isSystem = info.isSystemApp() || info.isUpdatedSystemApp();
-
-        if (isLegacy && isSystem) {
-            prefixRequiredLibrary(pkg, ANDROID_HIDL_BASE);
-            prefixRequiredLibrary(pkg, ANDROID_HIDL_MANAGER);
-        } else {
-            removeLibrary(pkg, ANDROID_HIDL_BASE);
-            removeLibrary(pkg, ANDROID_HIDL_MANAGER);
-        }
-    }
-}
diff --git a/core/java/android/content/pm/PackageInfo.java b/core/java/android/content/pm/PackageInfo.java
index d6fb28f..aa0002d 100644
--- a/core/java/android/content/pm/PackageInfo.java
+++ b/core/java/android/content/pm/PackageInfo.java
@@ -373,8 +373,9 @@
 
     /**
      * Whether the overlay is static, meaning it cannot be enabled/disabled at runtime.
+     * @hide
      */
-    boolean mOverlayIsStatic;
+    public boolean mOverlayIsStatic;
 
     /**
      * The user-visible SDK version (ex. 26) of the framework against which the application claims
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index cf21e96..65ee1e5 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -57,6 +57,12 @@
 import android.content.IntentFilter;
 import android.content.pm.PackageParserCacheHelper.ReadHelper;
 import android.content.pm.PackageParserCacheHelper.WriteHelper;
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.ApkParseUtils;
+import android.content.pm.parsing.ComponentParseUtils;
+import android.content.pm.parsing.PackageImpl;
+import android.content.pm.parsing.PackageInfoUtils;
+import android.content.pm.parsing.ParsedPackage;
 import android.content.pm.permission.SplitPermissionInfoParcelable;
 import android.content.pm.split.DefaultSplitAssetLoader;
 import android.content.pm.split.SplitAssetDependencyLoader;
@@ -67,7 +73,6 @@
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
-import android.net.Uri;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.FileUtils;
@@ -156,21 +161,22 @@
  * @hide
  */
 public class PackageParser {
-    private static final boolean DEBUG_JAR = false;
-    private static final boolean DEBUG_PARSER = false;
-    private static final boolean DEBUG_BACKUP = false;
-    private static final boolean LOG_PARSE_TIMINGS = Build.IS_DEBUGGABLE;
-    private static final int LOG_PARSE_TIMINGS_THRESHOLD_MS = 100;
+
+    public static final boolean DEBUG_JAR = false;
+    public static final boolean DEBUG_PARSER = false;
+    public static final boolean DEBUG_BACKUP = false;
+    public static final boolean LOG_PARSE_TIMINGS = Build.IS_DEBUGGABLE;
+    public static final int LOG_PARSE_TIMINGS_THRESHOLD_MS = 100;
 
     private static final String PROPERTY_CHILD_PACKAGES_ENABLED =
             "persist.sys.child_packages_enabled";
 
-    private static final boolean MULTI_PACKAGE_APK_ENABLED = Build.IS_DEBUGGABLE &&
+    public static final boolean MULTI_PACKAGE_APK_ENABLED = Build.IS_DEBUGGABLE &&
             SystemProperties.getBoolean(PROPERTY_CHILD_PACKAGES_ENABLED, false);
 
-    private static final float DEFAULT_PRE_O_MAX_ASPECT_RATIO = 1.86f;
-    private static final float DEFAULT_PRE_Q_MIN_ASPECT_RATIO = 1.333f;
-    private static final float DEFAULT_PRE_Q_MIN_ASPECT_RATIO_WATCH = 1f;
+    public static final float DEFAULT_PRE_O_MAX_ASPECT_RATIO = 1.86f;
+    public static final float DEFAULT_PRE_Q_MIN_ASPECT_RATIO = 1.333f;
+    public static final float DEFAULT_PRE_Q_MIN_ASPECT_RATIO_WATCH = 1f;
 
     private static final int DEFAULT_MIN_SDK_VERSION = 1;
     private static final int DEFAULT_TARGET_SDK_VERSION = 0;
@@ -182,37 +188,38 @@
     public static final String ANDROID_MANIFEST_FILENAME = "AndroidManifest.xml";
 
     /** Path prefix for apps on expanded storage */
-    private static final String MNT_EXPAND = "/mnt/expand/";
+    public static final String MNT_EXPAND = "/mnt/expand/";
 
-    private static final String TAG_MANIFEST = "manifest";
-    private static final String TAG_APPLICATION = "application";
-    private static final String TAG_PACKAGE_VERIFIER = "package-verifier";
-    private static final String TAG_OVERLAY = "overlay";
-    private static final String TAG_KEY_SETS = "key-sets";
-    private static final String TAG_PERMISSION_GROUP = "permission-group";
-    private static final String TAG_PERMISSION = "permission";
-    private static final String TAG_PERMISSION_TREE = "permission-tree";
-    private static final String TAG_USES_PERMISSION = "uses-permission";
-    private static final String TAG_USES_PERMISSION_SDK_M = "uses-permission-sdk-m";
-    private static final String TAG_USES_PERMISSION_SDK_23 = "uses-permission-sdk-23";
-    private static final String TAG_USES_CONFIGURATION = "uses-configuration";
-    private static final String TAG_USES_FEATURE = "uses-feature";
-    private static final String TAG_FEATURE_GROUP = "feature-group";
-    private static final String TAG_USES_SDK = "uses-sdk";
-    private static final String TAG_SUPPORT_SCREENS = "supports-screens";
-    private static final String TAG_PROTECTED_BROADCAST = "protected-broadcast";
-    private static final String TAG_INSTRUMENTATION = "instrumentation";
-    private static final String TAG_ORIGINAL_PACKAGE = "original-package";
-    private static final String TAG_ADOPT_PERMISSIONS = "adopt-permissions";
-    private static final String TAG_USES_GL_TEXTURE = "uses-gl-texture";
-    private static final String TAG_COMPATIBLE_SCREENS = "compatible-screens";
-    private static final String TAG_SUPPORTS_INPUT = "supports-input";
-    private static final String TAG_EAT_COMMENT = "eat-comment";
-    private static final String TAG_PACKAGE = "package";
-    private static final String TAG_RESTRICT_UPDATE = "restrict-update";
-    private static final String TAG_USES_SPLIT = "uses-split";
+    public static final String TAG_ADOPT_PERMISSIONS = "adopt-permissions";
+    public static final String TAG_APPLICATION = "application";
+    public static final String TAG_COMPATIBLE_SCREENS = "compatible-screens";
+    public static final String TAG_EAT_COMMENT = "eat-comment";
+    public static final String TAG_FEATURE_GROUP = "feature-group";
+    public static final String TAG_INSTRUMENTATION = "instrumentation";
+    public static final String TAG_KEY_SETS = "key-sets";
+    public static final String TAG_MANIFEST = "manifest";
+    public static final String TAG_ORIGINAL_PACKAGE = "original-package";
+    public static final String TAG_OVERLAY = "overlay";
+    public static final String TAG_PACKAGE = "package";
+    public static final String TAG_PACKAGE_VERIFIER = "package-verifier";
+    public static final String TAG_PERMISSION = "permission";
+    public static final String TAG_PERMISSION_GROUP = "permission-group";
+    public static final String TAG_PERMISSION_TREE = "permission-tree";
+    public static final String TAG_PROTECTED_BROADCAST = "protected-broadcast";
+    public static final String TAG_QUERIES = "queries";
+    public static final String TAG_RESTRICT_UPDATE = "restrict-update";
+    public static final String TAG_SUPPORT_SCREENS = "supports-screens";
+    public static final String TAG_SUPPORTS_INPUT = "supports-input";
+    public static final String TAG_USES_CONFIGURATION = "uses-configuration";
+    public static final String TAG_USES_FEATURE = "uses-feature";
+    public static final String TAG_USES_GL_TEXTURE = "uses-gl-texture";
+    public static final String TAG_USES_PERMISSION = "uses-permission";
+    public static final String TAG_USES_PERMISSION_SDK_23 = "uses-permission-sdk-23";
+    public static final String TAG_USES_PERMISSION_SDK_M = "uses-permission-sdk-m";
+    public static final String TAG_USES_SDK = "uses-sdk";
+    public static final String TAG_USES_SPLIT = "uses-split";
 
-    private static final String METADATA_MAX_ASPECT_RATIO = "android.max_aspect";
+    public static final String METADATA_MAX_ASPECT_RATIO = "android.max_aspect";
 
     /**
      * Bit mask of all the valid bits that can be set in recreateOnConfigChanges.
@@ -222,25 +229,25 @@
             ActivityInfo.CONFIG_MCC | ActivityInfo.CONFIG_MNC;
 
     // These are the tags supported by child packages
-    private static final Set<String> CHILD_PACKAGE_TAGS = new ArraySet<>();
+    public static final Set<String> CHILD_PACKAGE_TAGS = new ArraySet<>();
     static {
         CHILD_PACKAGE_TAGS.add(TAG_APPLICATION);
-        CHILD_PACKAGE_TAGS.add(TAG_USES_PERMISSION);
-        CHILD_PACKAGE_TAGS.add(TAG_USES_PERMISSION_SDK_M);
-        CHILD_PACKAGE_TAGS.add(TAG_USES_PERMISSION_SDK_23);
+        CHILD_PACKAGE_TAGS.add(TAG_COMPATIBLE_SCREENS);
+        CHILD_PACKAGE_TAGS.add(TAG_EAT_COMMENT);
+        CHILD_PACKAGE_TAGS.add(TAG_FEATURE_GROUP);
+        CHILD_PACKAGE_TAGS.add(TAG_INSTRUMENTATION);
+        CHILD_PACKAGE_TAGS.add(TAG_SUPPORT_SCREENS);
+        CHILD_PACKAGE_TAGS.add(TAG_SUPPORTS_INPUT);
         CHILD_PACKAGE_TAGS.add(TAG_USES_CONFIGURATION);
         CHILD_PACKAGE_TAGS.add(TAG_USES_FEATURE);
-        CHILD_PACKAGE_TAGS.add(TAG_FEATURE_GROUP);
-        CHILD_PACKAGE_TAGS.add(TAG_USES_SDK);
-        CHILD_PACKAGE_TAGS.add(TAG_SUPPORT_SCREENS);
-        CHILD_PACKAGE_TAGS.add(TAG_INSTRUMENTATION);
         CHILD_PACKAGE_TAGS.add(TAG_USES_GL_TEXTURE);
-        CHILD_PACKAGE_TAGS.add(TAG_COMPATIBLE_SCREENS);
-        CHILD_PACKAGE_TAGS.add(TAG_SUPPORTS_INPUT);
-        CHILD_PACKAGE_TAGS.add(TAG_EAT_COMMENT);
+        CHILD_PACKAGE_TAGS.add(TAG_USES_PERMISSION);
+        CHILD_PACKAGE_TAGS.add(TAG_USES_PERMISSION_SDK_23);
+        CHILD_PACKAGE_TAGS.add(TAG_USES_PERMISSION_SDK_M);
+        CHILD_PACKAGE_TAGS.add(TAG_USES_SDK);
     }
 
-    private static final boolean LOG_UNSAFE_BROADCASTS = false;
+    public static final boolean LOG_UNSAFE_BROADCASTS = false;
 
     /**
      * Total number of packages that were read from the cache.  We use it only for logging.
@@ -248,7 +255,7 @@
     public static final AtomicInteger sCachedPackageReadCount = new AtomicInteger();
 
     // Set of broadcast actions that are safe for manifest receivers
-    private static final Set<String> SAFE_BROADCASTS = new ArraySet<>();
+    public static final Set<String> SAFE_BROADCASTS = new ArraySet<>();
     static {
         SAFE_BROADCASTS.add(Intent.ACTION_BOOT_COMPLETED);
     }
@@ -295,26 +302,29 @@
      * @deprecated callers should move to explicitly passing around source path.
      */
     @Deprecated
-    private String mArchiveSourcePath;
+    public String mArchiveSourcePath;
 
-    private String[] mSeparateProcesses;
+    public String[] mSeparateProcesses;
     private boolean mOnlyCoreApps;
     private DisplayMetrics mMetrics;
     @UnsupportedAppUsage
-    private Callback mCallback;
+    public Callback mCallback;
     private File mCacheDir;
 
-    private static final int SDK_VERSION = Build.VERSION.SDK_INT;
-    private static final String[] SDK_CODENAMES = Build.VERSION.ACTIVE_CODENAMES;
+    public static final int SDK_VERSION = Build.VERSION.SDK_INT;
+    public static final String[] SDK_CODENAMES = Build.VERSION.ACTIVE_CODENAMES;
 
-    private int mParseError = PackageManager.INSTALL_SUCCEEDED;
+    public int mParseError = PackageManager.INSTALL_SUCCEEDED;
 
-    private static boolean sCompatibilityModeEnabled = true;
-    private static boolean sUseRoundIcon = false;
+    public ThreadLocal<ApkParseUtils.ParseResult> mSharedResult
+            = ThreadLocal.withInitial(ApkParseUtils.ParseResult::new);
 
-    private static final int PARSE_DEFAULT_INSTALL_LOCATION =
+    public static boolean sCompatibilityModeEnabled = true;
+    public static boolean sUseRoundIcon = false;
+
+    public static final int PARSE_DEFAULT_INSTALL_LOCATION =
             PackageInfo.INSTALL_LOCATION_UNSPECIFIED;
-    private static final int PARSE_DEFAULT_TARGET_SANDBOX = 1;
+    public static final int PARSE_DEFAULT_TARGET_SANDBOX = 1;
 
     static class ParsePackageItemArgs {
         final Package owner;
@@ -536,7 +546,7 @@
      *  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. */
-    private static final boolean RIGID_PARSER = false;
+    public static final boolean RIGID_PARSER = false;
 
     private static final String TAG = "PackageParser";
 
@@ -887,7 +897,7 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface ParseFlags {}
 
-    private static final Comparator<String> sSplitNameComparator = new SplitNameComparator();
+    public static final Comparator<String> sSplitNameComparator = new SplitNameComparator();
 
     /**
      * Used to sort a set of APKs based on their split names, always placing the
@@ -1033,7 +1043,7 @@
      * and unique split names.
      * <p>
      * Note that this <em>does not</em> perform signature verification; that
-     * must be done separately in {@link #collectCertificates(Package, int)}.
+     * must be done separately in {@link ApkParseUtils#collectCertificates(AndroidPackage, boolean)}.
      *
      * If {@code useCaches} is true, the package parser might return a cached
      * result from a previous parse of the same {@code packageFile} with the same
@@ -1041,21 +1051,54 @@
      * has changed since the last parse, it's up to callers to do so.
      *
      * @see #parsePackageLite(File, int)
+     * @deprecated use {@link #parseParsedPackage(File, int, boolean)}
      */
     @UnsupportedAppUsage
+    @Deprecated
     public Package parsePackage(File packageFile, int flags, boolean useCaches)
             throws PackageParserException {
-        Package parsed = useCaches ? getCachedResult(packageFile, flags) : null;
+        if (packageFile.isDirectory()) {
+            return parseClusterPackage(packageFile, flags);
+        } else {
+            return parseMonolithicPackage(packageFile, flags);
+        }
+    }
+
+    /**
+     * Equivalent to {@link #parsePackage(File, int, boolean)} with {@code useCaches == false}.
+     * @deprecated use {@link #parseParsedPackage(File, int, boolean)}
+     */
+    @UnsupportedAppUsage
+    @Deprecated
+    public Package parsePackage(File packageFile, int flags) throws PackageParserException {
+        return parsePackage(packageFile, flags, false /* useCaches */);
+    }
+
+    /**
+     * Updated method which returns {@link ParsedPackage}, the current representation of a
+     * package parsed from disk.
+     *
+     * @see #parsePackage(File, int, boolean)
+     */
+    public ParsedPackage parseParsedPackage(File packageFile, int flags, boolean useCaches)
+            throws PackageParserException {
+        ParsedPackage parsed = useCaches ? getCachedResult(packageFile, flags) : null;
         if (parsed != null) {
             return parsed;
         }
 
         long parseTime = LOG_PARSE_TIMINGS ? SystemClock.uptimeMillis() : 0;
-        if (packageFile.isDirectory()) {
-            parsed = parseClusterPackage(packageFile, flags);
-        } else {
-            parsed = parseMonolithicPackage(packageFile, flags);
-        }
+        ApkParseUtils.ParseInput parseInput = mSharedResult.get().reset();
+        parsed = ApkParseUtils.parsePackage(
+                parseInput,
+                mSeparateProcesses,
+                mCallback,
+                mMetrics,
+                mOnlyCoreApps,
+                packageFile,
+                flags
+        )
+                .hideAsParsed();
 
         long cacheTime = LOG_PARSE_TIMINGS ? SystemClock.uptimeMillis() : 0;
         cacheResult(packageFile, flags, parsed);
@@ -1067,19 +1110,12 @@
                         + "ms, update_cache=" + cacheTime + " ms");
             }
         }
+
         return parsed;
     }
 
     /**
-     * Equivalent to {@link #parsePackage(File, int, boolean)} with {@code useCaches == false}.
-     */
-    @UnsupportedAppUsage
-    public Package parsePackage(File packageFile, int flags) throws PackageParserException {
-        return parsePackage(packageFile, flags, false /* useCaches */);
-    }
-
-    /**
-     * Returns the cache key for a specificied {@code packageFile} and {@code flags}.
+     * Returns the cache key for a specified {@code packageFile} and {@code flags}.
      */
     private String getCacheKey(File packageFile, int flags) {
         StringBuilder sb = new StringBuilder(packageFile.getName());
@@ -1090,13 +1126,13 @@
     }
 
     @VisibleForTesting
-    protected Package fromCacheEntry(byte[] bytes) {
+    protected ParsedPackage fromCacheEntry(byte[] bytes) {
         return fromCacheEntryStatic(bytes);
     }
 
     /** static version of {@link #fromCacheEntry} for unit tests. */
     @VisibleForTesting
-    public static Package fromCacheEntryStatic(byte[] bytes) {
+    public static ParsedPackage fromCacheEntryStatic(byte[] bytes) {
         final Parcel p = Parcel.obtain();
         p.unmarshall(bytes, 0, bytes.length);
         p.setDataPosition(0);
@@ -1104,7 +1140,8 @@
         final ReadHelper helper = new ReadHelper(p);
         helper.startAndInstall();
 
-        PackageParser.Package pkg = new PackageParser.Package(p);
+        // TODO(b/135203078): Hide PackageImpl constructor?
+        ParsedPackage pkg = new PackageImpl(p);
 
         p.recycle();
 
@@ -1114,14 +1151,14 @@
     }
 
     @VisibleForTesting
-    protected byte[] toCacheEntry(Package pkg) {
+    protected byte[] toCacheEntry(ParsedPackage pkg) {
         return toCacheEntryStatic(pkg);
 
     }
 
     /** static version of {@link #toCacheEntry} for unit tests. */
     @VisibleForTesting
-    public static byte[] toCacheEntryStatic(Package pkg) {
+    public static byte[] toCacheEntryStatic(ParsedPackage pkg) {
         final Parcel p = Parcel.obtain();
         final WriteHelper helper = new WriteHelper(p);
 
@@ -1170,7 +1207,7 @@
      * Returns the cached parse result for {@code packageFile} for parse flags {@code flags},
      * or {@code null} if no cached result exists.
      */
-    private Package getCachedResult(File packageFile, int flags) {
+    public ParsedPackage getCachedResult(File packageFile, int flags) {
         if (mCacheDir == null) {
             return null;
         }
@@ -1199,7 +1236,7 @@
     /**
      * Caches the parse result for {@code packageFile} with flags {@code flags}.
      */
-    private void cacheResult(File packageFile, int flags, Package parsed) {
+    public void cacheResult(File packageFile, int flags, ParsedPackage parsed) {
         if (mCacheDir == null) {
             return;
         }
@@ -1238,7 +1275,8 @@
      * split names.
      * <p>
      * Note that this <em>does not</em> perform signature verification; that
-     * must be done separately in {@link #collectCertificates(Package, int)}.
+     * must be done separately in
+     * {@link ApkParseUtils#collectCertificates(AndroidPackage, boolean)}.
      */
     private Package parseClusterPackage(File packageDir, int flags) throws PackageParserException {
         final PackageLite lite = parseClusterPackageLite(packageDir, 0);
@@ -1302,10 +1340,11 @@
      * Parse the given APK file, treating it as as a single monolithic package.
      * <p>
      * Note that this <em>does not</em> perform signature verification; that
-     * must be done separately in {@link #collectCertificates(Package, int)}.
+     * must be done separately in
+     * {@link ApkParseUtils#collectCertificates(AndroidPackage, boolean)}.
      *
      * @deprecated external callers should move to
-     *             {@link #parsePackage(File, int)}. Eventually this method will
+     *             {@link #parseParsedPackage(File, int, boolean)}. Eventually this method will
      *             be marked private.
      */
     @Deprecated
@@ -1505,8 +1544,11 @@
      * Collect certificates from all the APKs described in the given package,
      * populating {@link Package#mSigningDetails}. Also asserts that all APK
      * contents are signed correctly and consistently.
+     *
+     * @deprecated use {@link ApkParseUtils#collectCertificates(AndroidPackage, boolean)}
      */
     @UnsupportedAppUsage
+    @Deprecated
     public static void collectCertificates(Package pkg, boolean skipVerify)
             throws PackageParserException {
         collectCertificatesInternal(pkg, skipVerify);
@@ -1685,7 +1727,7 @@
                 ? null : "must have at least one '.' separator";
     }
 
-    private static Pair<String, String> parsePackageSplitNames(XmlPullParser parser,
+    public static Pair<String, String> parsePackageSplitNames(XmlPullParser parser,
             AttributeSet attrs) throws IOException, XmlPullParserException,
             PackageParserException {
 
@@ -2454,8 +2496,6 @@
                 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                 return null;
 
-            } else if (tagName.equals("queries")) {
-                parseQueries(pkg, res, parser, flags, outError);
             } else {
                 Slog.w(TAG, "Unknown element under <manifest>: " + parser.getName()
                         + " at " + mArchiveSourcePath + " "
@@ -2925,7 +2965,7 @@
         return true;
     }
 
-    private static String buildClassName(String pkg, CharSequence clsSeq,
+    public static String buildClassName(String pkg, CharSequence clsSeq,
             String[] outError) {
         if (clsSeq == null || clsSeq.length() <= 0) {
             outError[0] = "Empty class name in package " + pkg;
@@ -2973,7 +3013,7 @@
         return proc;
     }
 
-    private static String buildProcessName(String pkg, String defProc,
+    public static String buildProcessName(String pkg, String defProc,
             CharSequence procSeq, int flags, String[] separateProcesses,
             String[] outError) {
         if ((flags&PARSE_IGNORE_PROCESSES) != 0 && !"system".equals(procSeq)) {
@@ -2993,7 +3033,7 @@
         return TextUtils.safeIntern(buildCompoundName(pkg, procSeq, "process", outError));
     }
 
-    private static String buildTaskAffinityName(String pkg, String defProc,
+    public static String buildTaskAffinityName(String pkg, String defProc,
             CharSequence procSeq, String[] outError) {
         if (procSeq == null) {
             return defProc;
@@ -3555,9 +3595,6 @@
             owner.mRequiredAccountType = requiredAccountType;
         }
 
-        owner.mForceQueryable =
-                sa.getBoolean(R.styleable.AndroidManifestApplication_forceQueryable, false);
-
         if (sa.getBoolean(
                 com.android.internal.R.styleable.AndroidManifestApplication_debuggable,
                 false)) {
@@ -4019,89 +4056,6 @@
         return true;
     }
 
-    private boolean parseQueries(Package owner, Resources res, XmlResourceParser parser, int flags,
-            String[] outError)
-            throws IOException, XmlPullParserException {
-
-        final int outerDepth = parser.getDepth();
-        int type;
-        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
-                && (type != XmlPullParser.END_TAG
-                || parser.getDepth() > outerDepth)) {
-            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
-                continue;
-            }
-            if (parser.getName().equals("intent")) {
-                QueriesIntentInfo intentInfo = new QueriesIntentInfo();
-                if (!parseIntent(res, parser, true /*allowGlobs*/, true /*allowAutoVerify*/,
-                        intentInfo, outError)) {
-                    return false;
-                }
-
-                Uri data = null;
-                String dataType = null;
-                String host = "";
-                final int numActions = intentInfo.countActions();
-                final int numSchemes = intentInfo.countDataSchemes();
-                final int numTypes = intentInfo.countDataTypes();
-                final int numHosts = intentInfo.getHosts().length;
-                if ((numSchemes == 0 && numTypes == 0 && numActions == 0)) {
-                    outError[0] = "intent tags must contain either an action or data.";
-                    return false;
-                }
-                if (numActions > 1) {
-                    outError[0] = "intent tag may have at most one action.";
-                    return false;
-                }
-                if (numTypes > 1) {
-                    outError[0] = "intent tag may have at most one data type.";
-                    return false;
-                }
-                if (numSchemes > 1) {
-                    outError[0] = "intent tag may have at most one data scheme.";
-                    return false;
-                }
-                if (numHosts > 1) {
-                    outError[0] = "intent tag may have at most one data host.";
-                    return false;
-                }
-                Intent intent = new Intent();
-                for (int i = 0, max = intentInfo.countCategories(); i < max; i++) {
-                    intent.addCategory(intentInfo.getCategory(i));
-                }
-                if (numHosts == 1) {
-                    host = intentInfo.getHosts()[0];
-                }
-                if (numSchemes == 1) {
-                    data = new Uri.Builder()
-                            .scheme(intentInfo.getDataScheme(0))
-                            .authority(host)
-                            .build();
-                }
-                if (numTypes == 1) {
-                    dataType = intentInfo.getDataType(0);
-                }
-                intent.setDataAndType(data, dataType);
-                if (numActions == 1) {
-                    intent.setAction(intentInfo.getAction(0));
-                }
-                owner.mQueriesIntents = ArrayUtils.add(owner.mQueriesIntents, intent);
-            } else if (parser.getName().equals("package")) {
-                final TypedArray sa = res.obtainAttributes(parser,
-                        com.android.internal.R.styleable.AndroidManifestQueriesPackage);
-                final String packageName =
-                        sa.getString(R.styleable.AndroidManifestQueriesPackage_name);
-                if (TextUtils.isEmpty(packageName)) {
-                    outError[0] = "Package name is missing from package tag.";
-                    return false;
-                }
-                owner.mQueriesPackages =
-                        ArrayUtils.add(owner.mQueriesPackages, packageName.intern());
-            }
-        }
-        return true;
-    }
-
     /**
      * Check if one of the IntentFilter as both actions DEFAULT / VIEW and a HTTP/HTTPS data URI
      */
@@ -5813,7 +5767,7 @@
         return null;
     }
 
-    private static final String ANDROID_RESOURCES
+    public static final String ANDROID_RESOURCES
             = "http://schemas.android.com/apk/res/android";
 
     private boolean parseIntent(Resources res, XmlResourceParser parser, boolean allowGlobs,
@@ -6508,7 +6462,10 @@
     /**
      * Representation of a full package parsed from APK files on disk. A package
      * consists of a single base APK, and zero or more split APKs.
+     *
+     * @deprecated use an {@link AndroidPackage}
      */
+    @Deprecated
     public final static class Package implements Parcelable {
 
         @UnsupportedAppUsage
@@ -6616,9 +6573,6 @@
         // The major version code declared for this package.
         public int mVersionCodeMajor;
 
-        // Whether the package declares that it should be queryable by all normal apps on device.
-        public boolean mForceQueryable;
-
         // Return long containing mVersionCode and mVersionCodeMajor.
         public long getLongVersionCode() {
             return PackageInfo.composeLongVersionCode(mVersionCodeMajor, mVersionCode);
@@ -6724,9 +6678,6 @@
         /** Whether or not the package is a stub and must be replaced by the full version. */
         public boolean isStub;
 
-        public ArrayList<String> mQueriesPackages;
-        public ArrayList<Intent> mQueriesIntents;
-
         @UnsupportedAppUsage
         public Package(String packageName) {
             this.packageName = packageName;
@@ -7230,9 +7181,6 @@
             use32bitAbi = (dest.readInt() == 1);
             restrictUpdateHash = dest.createByteArray();
             visibleToInstantApps = dest.readInt() == 1;
-            mForceQueryable = dest.readBoolean();
-            mQueriesIntents = dest.createTypedArrayList(Intent.CREATOR);
-            mQueriesPackages = dest.createStringArrayList();
         }
 
         private static void internStringArrayList(List<String> list) {
@@ -7248,7 +7196,7 @@
          * Sets the package owner and the the {@code applicationInfo} for every component
          * owner by this package.
          */
-        private void fixupOwner(List<? extends Component<?>> list) {
+        public void fixupOwner(List<? extends Component<?>> list) {
             if (list != null) {
                 for (Component<?> c : list) {
                     c.owner = this;
@@ -7358,12 +7306,8 @@
             dest.writeInt(use32bitAbi ? 1 : 0);
             dest.writeByteArray(restrictUpdateHash);
             dest.writeInt(visibleToInstantApps ? 1 : 0);
-            dest.writeBoolean(mForceQueryable);
-            dest.writeTypedList(mQueriesIntents);
-            dest.writeList(mQueriesPackages);
         }
 
-
         /**
          * Writes the keyset mapping to the provided package. {@code null} mappings are permitted.
          */
@@ -7435,6 +7379,10 @@
         };
     }
 
+    /**
+     * @deprecated use a {@link ComponentParseUtils.ParsedComponent}
+     */
+    @Deprecated
     public static abstract class Component<II extends IntentInfo> {
         @UnsupportedAppUsage
         public final ArrayList<II> intents;
@@ -7615,6 +7563,10 @@
         }
     }
 
+    /**
+     * @deprecated use {@link ComponentParseUtils.ParsedPermission}
+     */
+    @Deprecated
     public final static class Permission extends Component<IntentInfo> implements Parcelable {
         @UnsupportedAppUsage
         public final PermissionInfo info;
@@ -7689,6 +7641,10 @@
         };
     }
 
+    /**
+     * @deprecated use {@link ComponentParseUtils.ParsedPermissionGroup}
+     */
+    @Deprecated
     public final static class PermissionGroup extends Component<IntentInfo> implements Parcelable {
         @UnsupportedAppUsage
         public final PermissionGroupInfo info;
@@ -7788,7 +7744,12 @@
         return false;
     }
 
+    /**
+     * @deprecated use {@link PackageInfoUtils#generateApplicationInfo(
+     *      AndroidPackage, int, PackageUserState, int)}
+     */
     @UnsupportedAppUsage
+    @Deprecated
     public static ApplicationInfo generateApplicationInfo(Package p, int flags,
             PackageUserState state) {
         return generateApplicationInfo(p, flags, state, UserHandle.getCallingUserId());
@@ -7845,7 +7806,12 @@
         ai.icon = (sUseRoundIcon && ai.roundIconRes != 0) ? ai.roundIconRes : ai.iconRes;
     }
 
+    /**
+     * @deprecated use {@link PackageInfoUtils#generateApplicationInfo(
+     *      AndroidPackage, int, PackageUserState, int)}
+     */
     @UnsupportedAppUsage
+    @Deprecated
     public static ApplicationInfo generateApplicationInfo(Package p, int flags,
             PackageUserState state, int userId) {
         if (p == null) return null;
@@ -7885,6 +7851,11 @@
         return ai;
     }
 
+    /**
+     * @deprecated use {@link PackageInfoUtils#generateApplicationInfo(
+     *      AndroidPackage, int, PackageUserState, int)}
+     */
+    @Deprecated
     public static ApplicationInfo generateApplicationInfo(ApplicationInfo ai, int flags,
             PackageUserState state, int userId) {
         if (ai == null) return null;
@@ -7904,7 +7875,12 @@
         return ai;
     }
 
+    /**
+     * @deprecated use {@link PackageInfoUtils#generatePermissionInfo(
+     *      ComponentParseUtils.ParsedPermission, int)}
+     */
     @UnsupportedAppUsage
+    @Deprecated
     public static final PermissionInfo generatePermissionInfo(
             Permission p, int flags) {
         if (p == null) return null;
@@ -7916,7 +7892,12 @@
         return pi;
     }
 
+    /**
+     * @deprecated use {@link PackageInfoUtils#generatePermissionGroupInfo(
+     *      ComponentParseUtils.ParsedPermissionGroup, int)}
+     */
     @UnsupportedAppUsage
+    @Deprecated
     public static final PermissionGroupInfo generatePermissionGroupInfo(
             PermissionGroup pg, int flags) {
         if (pg == null) return null;
@@ -7928,6 +7909,10 @@
         return pgi;
     }
 
+    /**
+     * @deprecated use {@link ComponentParseUtils.ParsedActivity}
+     */
+    @Deprecated
     public final static class Activity extends Component<ActivityIntentInfo> implements Parcelable {
         @UnsupportedAppUsage
         public final ActivityInfo info;
@@ -8043,7 +8028,12 @@
         };
     }
 
+    /**
+     * @deprecated use {@link PackageInfoUtils#generateActivityInfo(
+     *      AndroidPackage, ComponentParseUtils.ParsedActivity, int, PackageUserState, int)}
+     */
     @UnsupportedAppUsage
+    @Deprecated
     public static final ActivityInfo generateActivityInfo(Activity a, int flags,
             PackageUserState state, int userId) {
         if (a == null) return null;
@@ -8061,6 +8051,11 @@
         return ai;
     }
 
+    /**
+     * @deprecated use {@link PackageInfoUtils#generateActivityInfo(
+     *      AndroidPackage, ComponentParseUtils.ParsedActivity, int, PackageUserState, int)}
+     */
+    @Deprecated
     public static final ActivityInfo generateActivityInfo(ActivityInfo ai, int flags,
             PackageUserState state, int userId) {
         if (ai == null) return null;
@@ -8074,6 +8069,10 @@
         return ai;
     }
 
+    /**
+     * @deprecated use {@link ComponentParseUtils.ParsedService}
+     */
+    @Deprecated
     public final static class Service extends Component<ServiceIntentInfo> implements Parcelable {
         @UnsupportedAppUsage
         public final ServiceInfo info;
@@ -8135,7 +8134,12 @@
         };
     }
 
+    /**
+     * @deprecated use {@link PackageInfoUtils#generateServiceInfo(
+     * AndroidPackage, ComponentParseUtils.ParsedService, int, PackageUserState, int)}
+     */
     @UnsupportedAppUsage
+    @Deprecated
     public static final ServiceInfo generateServiceInfo(Service s, int flags,
             PackageUserState state, int userId) {
         if (s == null) return null;
@@ -8153,6 +8157,10 @@
         return si;
     }
 
+    /**
+     * @deprecated use {@link ComponentParseUtils.ParsedProvider}
+     */
+    @Deprecated
     public final static class Provider extends Component<ProviderIntentInfo> implements Parcelable {
         @UnsupportedAppUsage
         public final ProviderInfo info;
@@ -8233,7 +8241,12 @@
         };
     }
 
+    /**
+     * @deprecated use {@link PackageInfoUtils#generateProviderInfo(
+     *      AndroidPackage, ComponentParseUtils.ParsedProvider, int, PackageUserState, int)}
+     */
     @UnsupportedAppUsage
+    @Deprecated
     public static final ProviderInfo generateProviderInfo(Provider p, int flags,
             PackageUserState state, int userId) {
         if (p == null) return null;
@@ -8256,6 +8269,10 @@
         return pi;
     }
 
+    /**
+     * @deprecated use {@link ComponentParseUtils.ParsedInstrumentation}
+     */
+    @Deprecated
     public final static class Instrumentation extends Component<IntentInfo> implements
             Parcelable {
         @UnsupportedAppUsage
@@ -8316,7 +8333,12 @@
         };
     }
 
+    /**
+     * @deprecated use {@link PackageInfoUtils#generateInstrumentationInfo(
+     *      ComponentParseUtils.ParsedInstrumentation, int)}
+     */
     @UnsupportedAppUsage
+    @Deprecated
     public static final InstrumentationInfo generateInstrumentationInfo(
             Instrumentation i, int flags) {
         if (i == null) return null;
@@ -8328,6 +8350,10 @@
         return ii;
     }
 
+    /**
+     * @deprecated use {@link ComponentParseUtils.ParsedIntentInfo}
+     */
+    @Deprecated
     public static abstract class IntentInfo extends IntentFilter {
         @UnsupportedAppUsage
         public boolean hasDefault;
@@ -8371,8 +8397,10 @@
         }
     }
 
-    public static final class QueriesIntentInfo extends IntentInfo {}
-
+    /**
+     * @deprecated use {@link ComponentParseUtils.ParsedActivityIntentInfo}
+     */
+    @Deprecated
     public final static class ActivityIntentInfo extends IntentInfo {
         @UnsupportedAppUsage
         public Activity activity;
@@ -8396,6 +8424,10 @@
         }
     }
 
+    /**
+     * @deprecated use {@link ComponentParseUtils.ParsedServiceIntentInfo}
+     */
+    @Deprecated
     public final static class ServiceIntentInfo extends IntentInfo {
         @UnsupportedAppUsage
         public Service service;
@@ -8419,6 +8451,10 @@
         }
     }
 
+    /**
+     * @deprecated use {@link ComponentParseUtils.ParsedProviderIntentInfo}
+     */
+    @Deprecated
     public static final class ProviderIntentInfo extends IntentInfo {
         @UnsupportedAppUsage
         public Provider provider;
diff --git a/core/java/android/content/pm/PackageSharedLibraryUpdater.java b/core/java/android/content/pm/PackageSharedLibraryUpdater.java
deleted file mode 100644
index 1565d9c..0000000
--- a/core/java/android/content/pm/PackageSharedLibraryUpdater.java
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.content.pm;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.ArrayUtils;
-
-import java.util.ArrayList;
-
-/**
- * Base for classes that update a {@link PackageParser.Package}'s shared libraries.
- *
- * @hide
- */
-@VisibleForTesting
-public abstract class PackageSharedLibraryUpdater {
-
-    /**
-     * Update the package's shared libraries.
-     *
-     * @param pkg the package to update.
-     */
-    public abstract void updatePackage(PackageParser.Package pkg);
-
-    static void removeLibrary(PackageParser.Package pkg, String libraryName) {
-        pkg.usesLibraries = ArrayUtils.remove(pkg.usesLibraries, libraryName);
-        pkg.usesOptionalLibraries =
-                ArrayUtils.remove(pkg.usesOptionalLibraries, libraryName);
-    }
-
-    static @NonNull
-            <T> ArrayList<T> prefix(@Nullable ArrayList<T> cur, T val) {
-        if (cur == null) {
-            cur = new ArrayList<>();
-        }
-        cur.add(0, val);
-        return cur;
-    }
-
-    private static boolean isLibraryPresent(ArrayList<String> usesLibraries,
-            ArrayList<String> usesOptionalLibraries, String apacheHttpLegacy) {
-        return ArrayUtils.contains(usesLibraries, apacheHttpLegacy)
-                || ArrayUtils.contains(usesOptionalLibraries, apacheHttpLegacy);
-    }
-
-    /**
-     * Add an implicit dependency.
-     *
-     * <p>If the package has an existing dependency on {@code existingLibrary} then prefix it with
-     * the {@code implicitDependency} if it is not already in the list of libraries.
-     *
-     * @param pkg the {@link PackageParser.Package} to update.
-     * @param existingLibrary the existing library.
-     * @param implicitDependency the implicit dependency to add
-     */
-    void prefixImplicitDependency(PackageParser.Package pkg, String existingLibrary,
-            String implicitDependency) {
-        ArrayList<String> usesLibraries = pkg.usesLibraries;
-        ArrayList<String> usesOptionalLibraries = pkg.usesOptionalLibraries;
-
-        if (!isLibraryPresent(usesLibraries, usesOptionalLibraries, implicitDependency)) {
-            if (ArrayUtils.contains(usesLibraries, existingLibrary)) {
-                prefix(usesLibraries, implicitDependency);
-            } else if (ArrayUtils.contains(usesOptionalLibraries, existingLibrary)) {
-                prefix(usesOptionalLibraries, implicitDependency);
-            }
-
-            pkg.usesLibraries = usesLibraries;
-            pkg.usesOptionalLibraries = usesOptionalLibraries;
-        }
-    }
-
-    void prefixRequiredLibrary(PackageParser.Package pkg, String libraryName) {
-        ArrayList<String> usesLibraries = pkg.usesLibraries;
-        ArrayList<String> usesOptionalLibraries = pkg.usesOptionalLibraries;
-
-        boolean alreadyPresent = isLibraryPresent(
-                usesLibraries, usesOptionalLibraries, libraryName);
-        if (!alreadyPresent) {
-            usesLibraries = prefix(usesLibraries, libraryName);
-
-            pkg.usesLibraries = usesLibraries;
-        }
-    }
-}
diff --git a/core/java/android/content/pm/PackageUserState.java b/core/java/android/content/pm/PackageUserState.java
index 5c74efb..55574c3 100644
--- a/core/java/android/content/pm/PackageUserState.java
+++ b/core/java/android/content/pm/PackageUserState.java
@@ -28,6 +28,7 @@
 import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
 
 import android.annotation.UnsupportedAppUsage;
+import android.content.pm.parsing.ComponentParseUtils;
 import android.os.BaseBundle;
 import android.os.Debug;
 import android.os.PersistableBundle;
@@ -127,6 +128,18 @@
                         && (!this.hidden || matchUninstalled));
     }
 
+    public boolean isMatch(ComponentInfo componentInfo, int flags) {
+        return isMatch(componentInfo.applicationInfo.isSystemApp(),
+                componentInfo.applicationInfo.enabled, componentInfo.enabled,
+                componentInfo.directBootAware, componentInfo.name, flags);
+    }
+
+    public boolean isMatch(boolean isSystem, boolean isPackageEnabled,
+            ComponentParseUtils.ParsedComponent component, int flags) {
+        return isMatch(isSystem, isPackageEnabled, component.isEnabled(),
+                component.isDirectBootAware(), component.getName(), flags);
+    }
+
     /**
      * Test if the given component is considered installed, enabled and a match
      * for the given flags.
@@ -135,28 +148,33 @@
      * Expects at least one of {@link PackageManager#MATCH_DIRECT_BOOT_AWARE} and
      * {@link PackageManager#MATCH_DIRECT_BOOT_UNAWARE} are specified in {@code flags}.
      * </p>
+     *
      */
-    public boolean isMatch(ComponentInfo componentInfo, int flags) {
-        final boolean isSystemApp = componentInfo.applicationInfo.isSystemApp();
+    public boolean isMatch(boolean isSystem, boolean isPackageEnabled, boolean isComponentEnabled,
+               boolean isComponentDirectBootAware, String componentName, int flags) {
         final boolean matchUninstalled = (flags & PackageManager.MATCH_KNOWN_PACKAGES) != 0;
-        if (!isAvailable(flags)
-                && !(isSystemApp && matchUninstalled)) return reportIfDebug(false, flags);
-        if (!isEnabled(componentInfo, flags)) return reportIfDebug(false, flags);
+        if (!isAvailable(flags) && !(isSystem && matchUninstalled)) {
+            return reportIfDebug(false, flags);
+        }
+
+        if (!isEnabled(isPackageEnabled, isComponentEnabled, componentName, flags)) {
+            return reportIfDebug(false, flags);
+        }
 
         if ((flags & MATCH_SYSTEM_ONLY) != 0) {
-            if (!isSystemApp) {
+            if (!isSystem) {
                 return reportIfDebug(false, flags);
             }
         }
 
         final boolean matchesUnaware = ((flags & MATCH_DIRECT_BOOT_UNAWARE) != 0)
-                && !componentInfo.directBootAware;
+                && !isComponentDirectBootAware;
         final boolean matchesAware = ((flags & MATCH_DIRECT_BOOT_AWARE) != 0)
-                && componentInfo.directBootAware;
+                && isComponentDirectBootAware;
         return reportIfDebug(matchesUnaware || matchesAware, flags);
     }
 
-    private boolean reportIfDebug(boolean result, int flags) {
+    public boolean reportIfDebug(boolean result, int flags) {
         if (DEBUG && !result) {
             Slog.i(LOG_TAG, "No match!; flags: "
                     + DebugUtils.flagsToString(PackageManager.class, "MATCH_", flags) + " "
@@ -165,10 +183,22 @@
         return result;
     }
 
+    public boolean isEnabled(ComponentInfo componentInfo, int flags) {
+        return isEnabled(componentInfo.applicationInfo.enabled, componentInfo.enabled,
+                componentInfo.name, flags);
+    }
+
+    public boolean isEnabled(boolean isPackageEnabled,
+            ComponentParseUtils.ParsedComponent parsedComponent, int flags) {
+        return isEnabled(isPackageEnabled, parsedComponent.isEnabled(), parsedComponent.getName(),
+                flags);
+    }
+
     /**
      * Test if the given component is considered enabled.
      */
-    public boolean isEnabled(ComponentInfo componentInfo, int flags) {
+    public boolean isEnabled(boolean isPackageEnabled, boolean isComponentEnabled,
+            String componentName, int flags) {
         if ((flags & MATCH_DISABLED_COMPONENTS) != 0) {
             return true;
         }
@@ -183,24 +213,26 @@
                 if ((flags & MATCH_DISABLED_UNTIL_USED_COMPONENTS) == 0) {
                     return false;
                 }
+                // fallthrough
             case COMPONENT_ENABLED_STATE_DEFAULT:
-                if (!componentInfo.applicationInfo.enabled) {
+                if (!isPackageEnabled) {
                     return false;
                 }
+                // fallthrough
             case COMPONENT_ENABLED_STATE_ENABLED:
                 break;
         }
 
         // Check if component has explicit state before falling through to
         // the manifest default
-        if (ArrayUtils.contains(this.enabledComponents, componentInfo.name)) {
+        if (ArrayUtils.contains(this.enabledComponents, componentName)) {
             return true;
         }
-        if (ArrayUtils.contains(this.disabledComponents, componentInfo.name)) {
+        if (ArrayUtils.contains(this.disabledComponents, componentName)) {
             return false;
         }
 
-        return componentInfo.enabled;
+        return isComponentEnabled;
     }
 
     @Override
diff --git a/core/java/android/content/pm/SharedLibraryInfo.java b/core/java/android/content/pm/SharedLibraryInfo.java
index 3488cc3..2863b26 100644
--- a/core/java/android/content/pm/SharedLibraryInfo.java
+++ b/core/java/android/content/pm/SharedLibraryInfo.java
@@ -20,6 +20,7 @@
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.content.pm.parsing.AndroidPackage;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -38,20 +39,24 @@
 public final class SharedLibraryInfo implements Parcelable {
 
     /** @hide */
-    public static SharedLibraryInfo createForStatic(PackageParser.Package pkg) {
-        return new SharedLibraryInfo(null, pkg.packageName, pkg.getAllCodePaths(),
-                pkg.staticSharedLibName,
-                pkg.staticSharedLibVersion,
+    public static SharedLibraryInfo createForStatic(AndroidPackage pkg) {
+        return new SharedLibraryInfo(null, pkg.getPackageName(),
+                pkg.makeListAllCodePaths(),
+                pkg.getStaticSharedLibName(),
+                pkg.getStaticSharedLibVersion(),
                 TYPE_STATIC,
-                new VersionedPackage(pkg.manifestPackageName, pkg.getLongVersionCode()),
+                new VersionedPackage(pkg.getManifestPackageName(),
+                        pkg.getLongVersionCode()),
                 null, null);
     }
 
     /** @hide */
-    public static SharedLibraryInfo createForDynamic(PackageParser.Package pkg, String name) {
-        return new SharedLibraryInfo(null, pkg.packageName, pkg.getAllCodePaths(), name,
+    public static SharedLibraryInfo createForDynamic(AndroidPackage pkg, String name) {
+        return new SharedLibraryInfo(null, pkg.getPackageName(),
+                pkg.makeListAllCodePaths(), name,
                 (long) VERSION_UNDEFINED,
-                TYPE_DYNAMIC, new VersionedPackage(pkg.packageName, pkg.getLongVersionCode()),
+                TYPE_DYNAMIC, new VersionedPackage(pkg.getPackageName(),
+                pkg.getLongVersionCode()),
                 null, null);
     }
 
diff --git a/core/java/android/content/pm/dex/DexMetadataHelper.java b/core/java/android/content/pm/dex/DexMetadataHelper.java
index 5d10b88..4cd201f 100644
--- a/core/java/android/content/pm/dex/DexMetadataHelper.java
+++ b/core/java/android/content/pm/dex/DexMetadataHelper.java
@@ -22,6 +22,7 @@
 import android.content.pm.PackageParser;
 import android.content.pm.PackageParser.PackageLite;
 import android.content.pm.PackageParser.PackageParserException;
+import android.content.pm.parsing.AndroidPackage;
 import android.util.ArrayMap;
 import android.util.jar.StrictJarFile;
 
@@ -86,8 +87,8 @@
      *
      * NOTE: involves I/O checks.
      */
-    public static Map<String, String> getPackageDexMetadata(PackageParser.Package pkg) {
-        return buildPackageApkToDexMetadataMap(pkg.getAllCodePaths());
+    public static Map<String, String> getPackageDexMetadata(AndroidPackage pkg) {
+        return buildPackageApkToDexMetadataMap(pkg.makeListAllCodePaths());
     }
 
     /**
@@ -160,7 +161,7 @@
      *
      * @throws PackageParserException in case of errors.
      */
-    public static void validatePackageDexMetadata(PackageParser.Package pkg)
+    public static void validatePackageDexMetadata(AndroidPackage pkg)
             throws PackageParserException {
         Collection<String> apkToDexMetadataList = getPackageDexMetadata(pkg).values();
         for (String dexMetadata : apkToDexMetadataList) {
diff --git a/core/java/android/content/pm/parsing/AndroidPackage.aidl b/core/java/android/content/pm/parsing/AndroidPackage.aidl
new file mode 100644
index 0000000..ab3cf7c
--- /dev/null
+++ b/core/java/android/content/pm/parsing/AndroidPackage.aidl
@@ -0,0 +1,21 @@
+/*
+**
+** Copyright 2019, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License")
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.content.pm.parsing;
+
+/* @hide */
+parcelable AndroidPackage;
diff --git a/core/java/android/content/pm/parsing/AndroidPackage.java b/core/java/android/content/pm/parsing/AndroidPackage.java
new file mode 100644
index 0000000..bef984d
--- /dev/null
+++ b/core/java/android/content/pm/parsing/AndroidPackage.java
@@ -0,0 +1,468 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.content.pm.parsing;
+
+import android.annotation.Nullable;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.ConfigurationInfo;
+import android.content.pm.FeatureGroupInfo;
+import android.content.pm.FeatureInfo;
+import android.content.pm.PackageParser;
+import android.content.pm.SharedLibraryInfo;
+import android.content.pm.parsing.ComponentParseUtils.ParsedActivity;
+import android.content.pm.parsing.ComponentParseUtils.ParsedActivityIntentInfo;
+import android.content.pm.parsing.ComponentParseUtils.ParsedInstrumentation;
+import android.content.pm.parsing.ComponentParseUtils.ParsedPermission;
+import android.content.pm.parsing.ComponentParseUtils.ParsedPermissionGroup;
+import android.content.pm.parsing.ComponentParseUtils.ParsedProvider;
+import android.content.pm.parsing.ComponentParseUtils.ParsedService;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.ArraySet;
+import android.util.SparseArray;
+
+import java.security.PublicKey;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+
+/**
+ * The last state of a package during parsing/install before it is available in
+ * {@link com.android.server.pm.PackageManagerService#mPackages}.
+ *
+ * It is the responsibility of the caller to understand what data is available at what step of the
+ * parsing or install process.
+ *
+ * TODO(b/135203078): Nullability annotations
+ * TODO(b/135203078): Remove get/setAppInfo differences
+ *
+ * @hide
+ */
+public interface AndroidPackage extends Parcelable {
+
+    /**
+     * This will eventually be removed. Avoid calling this at all costs.
+     */
+    @Deprecated
+    AndroidPackageWrite mutate();
+
+    boolean canHaveOatDir();
+
+    boolean cantSaveState();
+
+    List<String> getAdoptPermissions();
+
+    List<String> getAllCodePaths();
+
+    List<String> getAllCodePathsExcludingResourceOnly();
+
+    String getAppComponentFactory();
+
+    /**
+     * TODO(b/135203078): Use non-AppInfo method
+     * @deprecated use {@link #getClassLoaderName()}
+     */
+    @Deprecated
+    String getAppInfoClassLoaderName();
+
+    /**
+     * TODO(b/135203078): Use non-AppInfo method
+     * @deprecated use {@link #getCodePath()}
+     */
+    @Deprecated
+    String getAppInfoCodePath();
+
+    /**
+     * TODO(b/135203078): Use non-AppInfo method
+     * @deprecated use {@link #getName()}
+     */
+    @Deprecated
+    String getAppInfoName();
+
+    /**
+     * TODO(b/135203078): Use non-AppInfo method
+     * @deprecated use {@link #getPackageName()}
+     */
+    @Deprecated
+    String getAppInfoPackageName();
+
+    /**
+     * TODO(b/135203078): Use non-AppInfo method
+     * @deprecated use {@link #getProcessName()}
+     */
+    @Deprecated
+    String getAppInfoProcessName();
+
+    /**
+     * TODO(b/135203078): Use non-AppInfo method
+     * @deprecated use {@link #getCodePath()}
+     */
+    @Deprecated
+    String getAppInfoResourcePath();
+
+    Bundle getAppMetaData();
+
+    /**
+     * TODO(b/135203078): Use non-AppInfo method
+     * @deprecated use {@link #getVolumeUuid()}
+     */
+    @Deprecated
+    String getApplicationInfoVolumeUuid();
+
+    String getBackupAgentName();
+
+    int getBanner();
+
+    String getBaseCodePath();
+
+    int getBaseRevisionCode();
+
+    int getCategory();
+
+    String getClassLoaderName();
+
+    String getClassName();
+
+    String getCodePath();
+
+    int getCompatibleWidthLimitDp();
+
+    int getCompileSdkVersion();
+
+    String getCompileSdkVersionCodeName();
+
+    @Nullable
+    List<ConfigurationInfo> getConfigPreferences();
+
+    String getCpuAbiOverride();
+
+    String getCredentialProtectedDataDir();
+
+    String getDataDir();
+
+    int getDescriptionRes();
+
+    String getDeviceProtectedDataDir();
+
+    List<FeatureGroupInfo> getFeatureGroups();
+
+    int getFlags();
+
+    int getFullBackupContent();
+
+    int getHiddenApiEnforcementPolicy();
+
+    int getIcon();
+
+    int getIconRes();
+
+    List<String> getImplicitPermissions();
+
+    int getInstallLocation();
+
+    Map<String, ArraySet<PublicKey>> getKeySetMapping();
+
+    int getLabelRes();
+
+    int getLargestWidthLimitDp();
+
+    long[] getLastPackageUsageTimeInMills();
+
+    long getLatestForegroundPackageUseTimeInMills();
+
+    long getLatestPackageUseTimeInMills();
+
+    List<String> getLibraryNames();
+
+    int getLogo();
+
+    long getLongVersionCode();
+
+    String getManageSpaceActivityName();
+
+    String getManifestPackageName();
+
+    float getMaxAspectRatio();
+
+    Bundle getMetaData(); // TODO(b/135203078): Make all the Bundles immutable
+
+    float getMinAspectRatio();
+
+    int getMinSdkVersion();
+
+    String getName();
+
+    String getNativeLibraryDir();
+
+    String getNativeLibraryRootDir();
+
+    int getNetworkSecurityConfigRes();
+
+    CharSequence getNonLocalizedLabel();
+
+    @Nullable
+    List<String> getOriginalPackages();
+
+    String getOverlayCategory();
+
+    int getOverlayPriority();
+
+    String getOverlayTarget();
+
+    String getOverlayTargetName();
+
+    // TODO(b/135203078): Does this and getAppInfoPackageName have to be separate methods?
+    //  The refactor makes them the same value with no known consequences, so should be redundant.
+    String getPackageName();
+
+    @Nullable
+    List<ParsedActivity> getActivities();
+
+    @Nullable
+    List<ParsedInstrumentation> getInstrumentations();
+
+    @Nullable
+    List<ParsedPermissionGroup> getPermissionGroups();
+
+    @Nullable
+    List<ParsedPermission> getPermissions();
+
+    @Nullable
+    List<ParsedProvider> getProviders();
+
+    @Nullable
+    List<ParsedActivity> getReceivers();
+
+    @Nullable
+    List<ParsedService> getServices();
+
+    String getPermission();
+
+    @Nullable
+    List<ParsedActivityIntentInfo> getPreferredActivityFilters();
+
+    int getPreferredOrder();
+
+    String getPrimaryCpuAbi();
+
+    int getPrivateFlags();
+
+    String getProcessName();
+
+    @Nullable
+    List<String> getProtectedBroadcasts();
+
+    String getPublicSourceDir();
+
+    List<Intent> getQueriesIntents();
+
+    List<String> getQueriesPackages();
+
+    String getRealPackage();
+
+    // TODO(b/135203078): Rename to getRequiredFeatures? Somewhat ambigious whether "Req" is
+    //  required or requested.
+    @Nullable
+    List<FeatureInfo> getReqFeatures();
+
+    List<String> getRequestedPermissions();
+
+    String getRequiredAccountType();
+
+    int getRequiresSmallestWidthDp();
+
+    byte[] getRestrictUpdateHash();
+
+    String getRestrictedAccountType();
+
+    int getRoundIconRes();
+
+    String getScanPublicSourceDir();
+
+    String getScanSourceDir();
+
+    String getSeInfo();
+
+    String getSeInfoUser();
+
+    String getSecondaryCpuAbi();
+
+    String getSecondaryNativeLibraryDir();
+
+    String getSharedUserId();
+
+    int getSharedUserLabel();
+
+    PackageParser.SigningDetails getSigningDetails();
+
+    String[] getSplitClassLoaderNames();
+
+    @Nullable
+    String[] getSplitCodePaths();
+
+    @Nullable
+    SparseArray<int[]> getSplitDependencies();
+
+    int[] getSplitFlags();
+
+    String[] getSplitNames();
+
+    String[] getSplitPublicSourceDirs();
+
+    int[] getSplitRevisionCodes();
+
+    String getStaticSharedLibName();
+
+    long getStaticSharedLibVersion();
+
+    // TODO(b/135203078): Return String directly
+    UUID getStorageUuid();
+
+    int getTargetSandboxVersion();
+
+    int getTargetSdkVersion();
+
+    String getTaskAffinity();
+
+    int getTheme();
+
+    int getUiOptions();
+
+    int getUid();
+
+    Set<String> getUpgradeKeySets();
+
+    @Nullable
+    List<String> getUsesLibraries();
+
+    @Nullable
+    String[] getUsesLibraryFiles();
+
+    List<SharedLibraryInfo> getUsesLibraryInfos();
+
+    @Nullable
+    List<String> getUsesOptionalLibraries();
+
+    @Nullable
+    List<String> getUsesStaticLibraries();
+
+    @Nullable
+    String[][] getUsesStaticLibrariesCertDigests();
+
+    @Nullable
+    long[] getUsesStaticLibrariesVersions();
+
+    int getVersionCode();
+
+    int getVersionCodeMajor();
+
+    String getVersionName();
+
+    String getVolumeUuid();
+
+    String getZygotePreloadName();
+
+    boolean hasComponentClassName(String className);
+
+    // App Info
+
+    boolean hasRequestedLegacyExternalStorage();
+
+    boolean isBaseHardwareAccelerated();
+
+    boolean isCoreApp();
+
+    boolean isDefaultToDeviceProtectedStorage();
+
+    boolean isDirectBootAware();
+
+    boolean isEmbeddedDexUsed();
+
+    boolean isEnabled();
+
+    boolean isEncryptionAware();
+
+    boolean isExternal();
+
+    boolean isForceQueryable();
+
+    boolean isForwardLocked();
+
+    boolean isHiddenUntilInstalled();
+
+    boolean isInstantApp();
+
+    boolean isInternal();
+
+    boolean isLibrary();
+
+    // TODO(b/135203078): Should probably be in a utility class
+    boolean isMatch(int flags);
+
+    boolean isNativeLibraryRootRequiresIsa();
+
+    boolean isOem();
+
+    boolean isOverlayIsStatic();
+
+    boolean isPrivileged();
+
+    boolean isProduct();
+
+    boolean isProfileableByShell();
+
+    boolean isRequiredForAllUsers();
+
+    boolean isStaticSharedLibrary();
+
+    boolean isStub();
+
+    boolean isSystem(); // TODO(b/135203078): Collapse with isSystemApp, should be exactly the same.
+
+    boolean isSystemApp();
+
+    boolean isSystemExt();
+
+    boolean isUpdatedSystemApp();
+
+    boolean isUse32BitAbi();
+
+    boolean isVendor();
+
+    boolean isVisibleToInstantApps();
+
+    List<String> makeListAllCodePaths(); // TODO(b/135203078): Collapse with getAllCodePaths
+
+    boolean requestsIsolatedSplitLoading();
+
+    ApplicationInfo toAppInfo();
+
+    Creator<PackageImpl> CREATOR = new Creator<PackageImpl>() {
+        @Override
+        public PackageImpl createFromParcel(Parcel source) {
+            return new PackageImpl(source);
+        }
+
+        @Override
+        public PackageImpl[] newArray(int size) {
+            return new PackageImpl[size];
+        }
+    };
+}
diff --git a/core/java/android/content/pm/parsing/AndroidPackageWrite.java b/core/java/android/content/pm/parsing/AndroidPackageWrite.java
new file mode 100644
index 0000000..b7595d2
--- /dev/null
+++ b/core/java/android/content/pm/parsing/AndroidPackageWrite.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm.parsing;
+
+import android.annotation.Nullable;
+import android.content.pm.PackageParser;
+import android.content.pm.SharedLibraryInfo;
+
+import java.util.List;
+
+/**
+ * Contains remaining mutable fields after package parsing has completed.
+ *
+ * Most are state that can probably be tracked outside of the AndroidPackage object. New methods
+ * should never be added to this interface.
+ *
+ * TODO(b/135203078): Remove entirely
+ *
+ * @deprecated the eventual goal is that the object returned from parsing represents exactly what
+ * was parsed from the APK, and so further mutation should be disallowed,
+ * with any state being stored in another class
+ *
+ * @hide
+ */
+@Deprecated
+public interface AndroidPackageWrite extends AndroidPackage {
+
+    AndroidPackageWrite setUsesLibraryFiles(@Nullable String[] usesLibraryFiles);
+
+    // TODO(b/135203078): Remove or use a non-system wide representation of the shared libraries;
+    //  this doesn't represent what was parsed from the APK
+    AndroidPackageWrite setUsesLibraryInfos(@Nullable List<SharedLibraryInfo> usesLibraryInfos);
+
+    AndroidPackageWrite setHiddenUntilInstalled(boolean hidden);
+
+    AndroidPackageWrite setUpdatedSystemApp(boolean updatedSystemApp);
+
+    AndroidPackageWrite setLastPackageUsageTimeInMills(int reason, long time);
+
+    AndroidPackageWrite setPrimaryCpuAbi(String primaryCpuAbi);
+
+    AndroidPackageWrite setSeInfo(String seInfo);
+
+    AndroidPackageWrite setSigningDetails(PackageParser.SigningDetails signingDetails);
+}
diff --git a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
new file mode 100644
index 0000000..ac2e373
--- /dev/null
+++ b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
@@ -0,0 +1,428 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm.parsing;
+
+import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
+
+import android.annotation.UnsupportedAppUsage;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageParser;
+import android.content.pm.VerifierInfo;
+import android.content.res.ApkAssets;
+import android.content.res.XmlResourceParser;
+import android.os.Trace;
+import android.util.ArrayMap;
+import android.util.AttributeSet;
+import android.util.Pair;
+import android.util.Slog;
+
+import com.android.internal.R;
+import com.android.internal.util.ArrayUtils;
+
+import libcore.io.IoUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.security.PublicKey;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/** @hide */
+public class ApkLiteParseUtils {
+
+    private static final String TAG = ApkParseUtils.TAG;
+
+    // TODO(b/135203078): Consolidate constants
+    private static final int DEFAULT_MIN_SDK_VERSION = 1;
+    private static final int DEFAULT_TARGET_SDK_VERSION = 0;
+
+    private static final int PARSE_DEFAULT_INSTALL_LOCATION =
+            PackageInfo.INSTALL_LOCATION_UNSPECIFIED;
+
+    /**
+     * Parse only lightweight details about the package at the given location.
+     * Automatically detects if the package is a monolithic style (single APK
+     * file) or cluster style (directory of APKs).
+     * <p>
+     * This performs sanity checking on cluster style packages, such as
+     * requiring identical package name and version codes, a single base APK,
+     * and unique split names.
+     *
+     * @see PackageParser#parsePackage(File, int)
+     */
+    @UnsupportedAppUsage
+    public static PackageParser.PackageLite parsePackageLite(File packageFile, int flags)
+            throws PackageParser.PackageParserException {
+        if (packageFile.isDirectory()) {
+            return parseClusterPackageLite(packageFile, flags);
+        } else {
+            return parseMonolithicPackageLite(packageFile, flags);
+        }
+    }
+
+    public static PackageParser.PackageLite parseMonolithicPackageLite(File packageFile, int flags)
+            throws PackageParser.PackageParserException {
+        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parseApkLite");
+        final PackageParser.ApkLite baseApk = parseApkLite(packageFile, flags);
+        final String packagePath = packageFile.getAbsolutePath();
+        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+        return new PackageParser.PackageLite(packagePath, baseApk, null, null, null, null,
+                null, null);
+    }
+
+    public static PackageParser.PackageLite parseClusterPackageLite(File packageDir, int flags)
+            throws PackageParser.PackageParserException {
+        final File[] files = packageDir.listFiles();
+        if (ArrayUtils.isEmpty(files)) {
+            throw new PackageParser.PackageParserException(
+                    PackageManager.INSTALL_PARSE_FAILED_NOT_APK, "No packages found in split");
+        }
+
+        String packageName = null;
+        int versionCode = 0;
+
+        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parseApkLite");
+        final ArrayMap<String, PackageParser.ApkLite> apks = new ArrayMap<>();
+        for (File file : files) {
+            if (PackageParser.isApkFile(file)) {
+                final PackageParser.ApkLite lite = parseApkLite(file, flags);
+
+                // Assert that all package names and version codes are
+                // consistent with the first one we encounter.
+                if (packageName == null) {
+                    packageName = lite.packageName;
+                    versionCode = lite.versionCode;
+                } else {
+                    if (!packageName.equals(lite.packageName)) {
+                        throw new PackageParser.PackageParserException(
+                                PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST,
+                                "Inconsistent package " + lite.packageName + " in " + file
+                                        + "; expected " + packageName);
+                    }
+                    if (versionCode != lite.versionCode) {
+                        throw new PackageParser.PackageParserException(
+                                PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST,
+                                "Inconsistent version " + lite.versionCode + " in " + file
+                                        + "; expected " + versionCode);
+                    }
+                }
+
+                // Assert that each split is defined only oncuses-static-libe
+                if (apks.put(lite.splitName, lite) != null) {
+                    throw new PackageParser.PackageParserException(
+                            PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST,
+                            "Split name " + lite.splitName
+                                    + " defined more than once; most recent was " + file);
+                }
+            }
+        }
+        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+
+        final PackageParser.ApkLite baseApk = apks.remove(null);
+        if (baseApk == null) {
+            throw new PackageParser.PackageParserException(
+                    PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST,
+                    "Missing base APK in " + packageDir);
+        }
+
+        // Always apply deterministic ordering based on splitName
+        final int size = apks.size();
+
+        String[] splitNames = null;
+        boolean[] isFeatureSplits = null;
+        String[] usesSplitNames = null;
+        String[] configForSplits = null;
+        String[] splitCodePaths = null;
+        int[] splitRevisionCodes = null;
+        if (size > 0) {
+            splitNames = new String[size];
+            isFeatureSplits = new boolean[size];
+            usesSplitNames = new String[size];
+            configForSplits = new String[size];
+            splitCodePaths = new String[size];
+            splitRevisionCodes = new int[size];
+
+            splitNames = apks.keySet().toArray(splitNames);
+            Arrays.sort(splitNames, PackageParser.sSplitNameComparator);
+
+            for (int i = 0; i < size; i++) {
+                final PackageParser.ApkLite apk = apks.get(splitNames[i]);
+                usesSplitNames[i] = apk.usesSplitName;
+                isFeatureSplits[i] = apk.isFeatureSplit;
+                configForSplits[i] = apk.configForSplit;
+                splitCodePaths[i] = apk.codePath;
+                splitRevisionCodes[i] = apk.revisionCode;
+            }
+        }
+
+        final String codePath = packageDir.getAbsolutePath();
+        return new PackageParser.PackageLite(codePath, baseApk, splitNames, isFeatureSplits,
+                usesSplitNames, configForSplits, splitCodePaths, splitRevisionCodes);
+    }
+
+    /**
+     * Utility method that retrieves lightweight details about a single APK
+     * file, including package name, split name, and install location.
+     *
+     * @param apkFile path to a single APK
+     * @param flags optional parse flags, such as
+     *            {@link PackageParser#PARSE_COLLECT_CERTIFICATES}
+     */
+    public static PackageParser.ApkLite parseApkLite(File apkFile, int flags)
+            throws PackageParser.PackageParserException {
+        return parseApkLiteInner(apkFile, null, null, flags);
+    }
+
+    /**
+     * Utility method that retrieves lightweight details about a single APK
+     * file, including package name, split name, and install location.
+     *
+     * @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}
+     */
+    public static PackageParser.ApkLite parseApkLite(FileDescriptor fd, String debugPathName,
+            int flags) throws PackageParser.PackageParserException {
+        return parseApkLiteInner(null, fd, debugPathName, flags);
+    }
+
+    private static PackageParser.ApkLite parseApkLiteInner(File apkFile, FileDescriptor fd,
+            String debugPathName, int flags) throws PackageParser.PackageParserException {
+        final String apkPath = fd != null ? debugPathName : apkFile.getAbsolutePath();
+
+        XmlResourceParser parser = null;
+        ApkAssets apkAssets = null;
+        try {
+            try {
+                apkAssets = fd != null
+                        ? ApkAssets.loadFromFd(fd, debugPathName, false, false)
+                        : ApkAssets.loadFromPath(apkPath);
+            } catch (IOException e) {
+                throw new PackageParser.PackageParserException(
+                        PackageManager.INSTALL_PARSE_FAILED_NOT_APK,
+                        "Failed to parse " + apkPath, e);
+            }
+
+            parser = apkAssets.openXml(PackageParser.ANDROID_MANIFEST_FILENAME);
+
+            final PackageParser.SigningDetails signingDetails;
+            if ((flags & PackageParser.PARSE_COLLECT_CERTIFICATES) != 0) {
+                final boolean skipVerify = (flags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0;
+                Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates");
+                try {
+                    signingDetails =
+                            ApkParseUtils.collectCertificates(apkFile.getAbsolutePath(), skipVerify,
+                                    false, PackageParser.SigningDetails.UNKNOWN);
+                } finally {
+                    Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+                }
+            } else {
+                signingDetails = PackageParser.SigningDetails.UNKNOWN;
+            }
+
+            final AttributeSet attrs = parser;
+            return parseApkLite(apkPath, parser, attrs, signingDetails);
+
+        } catch (XmlPullParserException | IOException | RuntimeException e) {
+            Slog.w(TAG, "Failed to parse " + apkPath, e);
+            throw new PackageParser.PackageParserException(
+                    PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
+                    "Failed to parse " + apkPath, e);
+        } finally {
+            IoUtils.closeQuietly(parser);
+            if (apkAssets != null) {
+                try {
+                    apkAssets.close();
+                } catch (Throwable ignored) {
+                }
+            }
+            // TODO(b/72056911): Implement AutoCloseable on ApkAssets.
+        }
+    }
+
+    private static PackageParser.ApkLite parseApkLite(
+            String codePath, XmlPullParser parser, AttributeSet attrs,
+            PackageParser.SigningDetails signingDetails)
+            throws IOException, XmlPullParserException, PackageParser.PackageParserException {
+        final Pair<String, String> packageSplit = PackageParser.parsePackageSplitNames(
+                parser, attrs);
+
+        int installLocation = PARSE_DEFAULT_INSTALL_LOCATION;
+        int versionCode = 0;
+        int versionCodeMajor = 0;
+        int targetSdkVersion = DEFAULT_TARGET_SDK_VERSION;
+        int minSdkVersion = DEFAULT_MIN_SDK_VERSION;
+        int revisionCode = 0;
+        boolean coreApp = false;
+        boolean debuggable = false;
+        boolean multiArch = false;
+        boolean use32bitAbi = false;
+        boolean extractNativeLibs = true;
+        boolean isolatedSplits = false;
+        boolean isFeatureSplit = false;
+        boolean isSplitRequired = false;
+        boolean useEmbeddedDex = false;
+        String configForSplit = null;
+        String usesSplitName = null;
+
+        for (int i = 0; i < attrs.getAttributeCount(); i++) {
+            final String attr = attrs.getAttributeName(i);
+            switch (attr) {
+                case "installLocation":
+                    installLocation = attrs.getAttributeIntValue(i,
+                            PARSE_DEFAULT_INSTALL_LOCATION);
+                    break;
+                case "versionCode":
+                    versionCode = attrs.getAttributeIntValue(i, 0);
+                    break;
+                case "versionCodeMajor":
+                    versionCodeMajor = attrs.getAttributeIntValue(i, 0);
+                    break;
+                case "revisionCode":
+                    revisionCode = attrs.getAttributeIntValue(i, 0);
+                    break;
+                case "coreApp":
+                    coreApp = attrs.getAttributeBooleanValue(i, false);
+                    break;
+                case "isolatedSplits":
+                    isolatedSplits = attrs.getAttributeBooleanValue(i, false);
+                    break;
+                case "configForSplit":
+                    configForSplit = attrs.getAttributeValue(i);
+                    break;
+                case "isFeatureSplit":
+                    isFeatureSplit = attrs.getAttributeBooleanValue(i, false);
+                    break;
+                case "isSplitRequired":
+                    isSplitRequired = attrs.getAttributeBooleanValue(i, false);
+                    break;
+            }
+        }
+
+        // Only search the tree when the tag is the direct child of <manifest> tag
+        int type;
+        final int searchDepth = parser.getDepth() + 1;
+
+        final List<VerifierInfo> verifiers = new ArrayList<>();
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG || parser.getDepth() >= searchDepth)) {
+            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                continue;
+            }
+
+            if (parser.getDepth() != searchDepth) {
+                continue;
+            }
+
+            if (PackageParser.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())) {
+                for (int i = 0; i < attrs.getAttributeCount(); ++i) {
+                    final String attr = attrs.getAttributeName(i);
+                    switch (attr) {
+                        case "debuggable":
+                            debuggable = attrs.getAttributeBooleanValue(i, false);
+                            break;
+                        case "multiArch":
+                            multiArch = attrs.getAttributeBooleanValue(i, false);
+                            break;
+                        case "use32bitAbi":
+                            use32bitAbi = attrs.getAttributeBooleanValue(i, false);
+                            break;
+                        case "extractNativeLibs":
+                            extractNativeLibs = attrs.getAttributeBooleanValue(i, true);
+                            break;
+                        case "useEmbeddedDex":
+                            useEmbeddedDex = attrs.getAttributeBooleanValue(i, false);
+                            break;
+                    }
+                }
+            } else if (PackageParser.TAG_USES_SPLIT.equals(parser.getName())) {
+                if (usesSplitName != null) {
+                    Slog.w(TAG, "Only one <uses-split> permitted. Ignoring others.");
+                    continue;
+                }
+
+                usesSplitName = attrs.getAttributeValue(PackageParser.ANDROID_RESOURCES, "name");
+                if (usesSplitName == null) {
+                    throw new PackageParser.PackageParserException(
+                            PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                            "<uses-split> tag requires 'android:name' attribute");
+                }
+            } else if (PackageParser.TAG_USES_SDK.equals(parser.getName())) {
+                for (int i = 0; i < attrs.getAttributeCount(); ++i) {
+                    final String attr = attrs.getAttributeName(i);
+                    if ("targetSdkVersion".equals(attr)) {
+                        targetSdkVersion = attrs.getAttributeIntValue(i,
+                                DEFAULT_TARGET_SDK_VERSION);
+                    }
+                    if ("minSdkVersion".equals(attr)) {
+                        minSdkVersion = attrs.getAttributeIntValue(i, DEFAULT_MIN_SDK_VERSION);
+                    }
+                }
+            }
+        }
+
+        return new PackageParser.ApkLite(codePath, packageSplit.first, packageSplit.second,
+                isFeatureSplit, configForSplit, usesSplitName, isSplitRequired, versionCode,
+                versionCodeMajor, revisionCode, installLocation, verifiers, signingDetails,
+                coreApp, debuggable, multiArch, use32bitAbi, useEmbeddedDex, extractNativeLibs,
+                isolatedSplits, minSdkVersion, targetSdkVersion);
+    }
+
+    public static VerifierInfo parseVerifier(AttributeSet attrs) {
+        String packageName = null;
+        String encodedPublicKey = null;
+
+        final int attrCount = attrs.getAttributeCount();
+        for (int i = 0; i < attrCount; i++) {
+            final int attrResId = attrs.getAttributeNameResource(i);
+            switch (attrResId) {
+                case R.attr.name:
+                    packageName = attrs.getAttributeValue(i);
+                    break;
+
+                case R.attr.publicKey:
+                    encodedPublicKey = attrs.getAttributeValue(i);
+                    break;
+            }
+        }
+
+        if (packageName == null || packageName.length() == 0) {
+            Slog.i(TAG, "verifier package name was null; skipping");
+            return null;
+        }
+
+        final PublicKey publicKey = PackageParser.parsePublicKey(encodedPublicKey);
+        if (publicKey == null) {
+            Slog.i(TAG, "Unable to parse verifier public key for " + packageName);
+            return null;
+        }
+
+        return new VerifierInfo(packageName, publicKey);
+    }
+}
diff --git a/core/java/android/content/pm/parsing/ApkParseUtils.java b/core/java/android/content/pm/parsing/ApkParseUtils.java
new file mode 100644
index 0000000..0f35b27
--- /dev/null
+++ b/core/java/android/content/pm/parsing/ApkParseUtils.java
@@ -0,0 +1,3197 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm.parsing;
+
+import static android.content.pm.ActivityInfo.FLAG_SUPPORTS_PICTURE_IN_PICTURE;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.content.pm.PackageManager.FEATURE_WATCH;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NOT_APK;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION;
+import static android.os.Build.VERSION_CODES.O;
+import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
+import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.ActivityTaskManager;
+import android.app.ActivityThread;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.ConfigurationInfo;
+import android.content.pm.FeatureGroupInfo;
+import android.content.pm.FeatureInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageItemInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageParser;
+import android.content.pm.PackageParser.PackageParserException;
+import android.content.pm.PackageParser.SigningDetails;
+import android.content.pm.Signature;
+import android.content.pm.permission.SplitPermissionInfoParcelable;
+import android.content.pm.split.DefaultSplitAssetLoader;
+import android.content.pm.split.SplitAssetDependencyLoader;
+import android.content.pm.split.SplitAssetLoader;
+import android.content.res.AssetManager;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.FileUtils;
+import android.os.RemoteException;
+import android.os.SystemProperties;
+import android.os.Trace;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.util.Pair;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.util.TypedValue;
+import android.util.apk.ApkSignatureVerifier;
+
+import com.android.internal.R;
+import com.android.internal.os.ClassLoaderFactory;
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.XmlUtils;
+
+import libcore.io.IoUtils;
+import libcore.util.EmptyArray;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.File;
+import java.io.IOException;
+import java.security.PublicKey;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+
+/** @hide */
+public class ApkParseUtils {
+
+    // TODO(b/135203078): Consolidate log tags
+    static final String TAG = "PackageParsing";
+
+    /**
+     * Parse the package at the given location. Automatically detects if the
+     * package is a monolithic style (single APK file) or cluster style
+     * (directory of APKs).
+     * <p>
+     * This performs sanity checking on cluster style packages, such as
+     * requiring identical package name and version codes, a single base APK,
+     * and unique split names.
+     * <p>
+     * Note that this <em>does not</em> perform signature verification; that
+     * must be done separately in {@link #collectCertificates(ParsedPackage, boolean)}.
+     *
+     * If {@code useCaches} is true, the package parser might return a cached
+     * result from a previous parse of the same {@code packageFile} with the same
+     * {@code flags}. Note that this method does not check whether {@code packageFile}
+     * has changed since the last parse, it's up to callers to do so.
+     *
+     * @see PackageParser#parsePackageLite(File, int)
+     */
+    public static ParsingPackage parsePackage(
+            ParseInput parseInput,
+            String[] separateProcesses,
+            PackageParser.Callback callback,
+            DisplayMetrics displayMetrics,
+            boolean onlyCoreApps,
+            File packageFile,
+            int flags
+    ) throws PackageParserException {
+        if (packageFile.isDirectory()) {
+            return parseClusterPackage(parseInput, separateProcesses, callback, displayMetrics,
+                    onlyCoreApps, packageFile, flags);
+        } else {
+            return parseMonolithicPackage(parseInput, separateProcesses, callback, displayMetrics,
+                    onlyCoreApps, packageFile, flags);
+        }
+    }
+
+    /**
+     * Parse all APKs contained in the given directory, treating them as a
+     * single package. This also performs sanity checking, such as requiring
+     * identical package name and version codes, a single base APK, and unique
+     * split names.
+     * <p>
+     * Note that this <em>does not</em> perform signature verification; that
+     * must be done separately in {@link #collectCertificates(ParsedPackage, boolean)}.
+     */
+    private static ParsingPackage parseClusterPackage(
+            ParseInput parseInput,
+            String[] separateProcesses,
+            PackageParser.Callback callback,
+            DisplayMetrics displayMetrics,
+            boolean onlyCoreApps,
+            File packageDir,
+            int flags
+    ) throws PackageParserException {
+        final PackageParser.PackageLite lite = ApkLiteParseUtils.parseClusterPackageLite(packageDir,
+                0);
+        if (onlyCoreApps && !lite.coreApp) {
+            throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                    "Not a coreApp: " + packageDir);
+        }
+
+        // Build the split dependency tree.
+        SparseArray<int[]> splitDependencies = null;
+        final SplitAssetLoader assetLoader;
+        if (lite.isolatedSplits && !ArrayUtils.isEmpty(lite.splitNames)) {
+            try {
+                splitDependencies = SplitAssetDependencyLoader.createDependenciesFromPackage(lite);
+                assetLoader = new SplitAssetDependencyLoader(lite, splitDependencies, flags);
+            } catch (SplitAssetDependencyLoader.IllegalDependencyException e) {
+                throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST, e.getMessage());
+            }
+        } else {
+            assetLoader = new DefaultSplitAssetLoader(lite, flags);
+        }
+
+        try {
+            final AssetManager assets = assetLoader.getBaseAssetManager();
+            final File baseApk = new File(lite.baseCodePath);
+            ParsingPackage parsingPackage = parseBaseApk(parseInput, separateProcesses, callback,
+                    displayMetrics, baseApk, assets, flags);
+            if (parsingPackage == null) {
+                throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
+                        "Failed to parse base APK: " + baseApk);
+            }
+
+            if (!ArrayUtils.isEmpty(lite.splitNames)) {
+                parsingPackage.asSplit(
+                        lite.splitNames,
+                        lite.splitCodePaths,
+                        lite.splitRevisionCodes,
+                        splitDependencies
+                );
+                final int num = lite.splitNames.length;
+
+                for (int i = 0; i < num; i++) {
+                    final AssetManager splitAssets = assetLoader.getSplitAssetManager(i);
+                    parseSplitApk(parseInput, displayMetrics, separateProcesses, parsingPackage, i,
+                            splitAssets, flags);
+                }
+            }
+
+            return parsingPackage.setCodePath(packageDir.getCanonicalPath())
+                    .setUse32BitAbi(lite.use32bitAbi);
+        } catch (IOException e) {
+            throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
+                    "Failed to get path: " + lite.baseCodePath, e);
+        } finally {
+            IoUtils.closeQuietly(assetLoader);
+        }
+    }
+
+    /**
+     * Parse the given APK file, treating it as as a single monolithic package.
+     * <p>
+     * Note that this <em>does not</em> perform signature verification; that
+     * must be done separately in {@link #collectCertificates(AndroidPackage, boolean)}.
+     */
+    public static ParsingPackage parseMonolithicPackage(
+            ParseInput parseInput,
+            String[] separateProcesses,
+            PackageParser.Callback callback,
+            DisplayMetrics displayMetrics,
+            boolean onlyCoreApps,
+            File apkFile,
+            int flags
+    ) throws PackageParserException {
+        final PackageParser.PackageLite lite = ApkLiteParseUtils.parseMonolithicPackageLite(apkFile,
+                flags);
+        if (onlyCoreApps) {
+            if (!lite.coreApp) {
+                throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                        "Not a coreApp: " + apkFile);
+            }
+        }
+
+        final SplitAssetLoader assetLoader = new DefaultSplitAssetLoader(lite, flags);
+        try {
+            return parseBaseApk(parseInput, separateProcesses, callback,
+                    displayMetrics, apkFile, assetLoader.getBaseAssetManager(), flags)
+                    .setCodePath(apkFile.getCanonicalPath())
+                    .setUse32BitAbi(lite.use32bitAbi);
+        } catch (IOException e) {
+            throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
+                    "Failed to get path: " + apkFile, e);
+        } finally {
+            IoUtils.closeQuietly(assetLoader);
+        }
+    }
+
+    private static ParsingPackage parseBaseApk(
+            ParseInput parseInput,
+            String[] separateProcesses,
+            PackageParser.Callback callback,
+            DisplayMetrics displayMetrics,
+            File apkFile,
+            AssetManager assets,
+            int flags
+    ) throws PackageParserException {
+        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 (PackageParser.DEBUG_JAR) Slog.d(TAG, "Scanning base APK: " + apkPath);
+
+        XmlResourceParser parser = null;
+        try {
+            final int cookie = assets.findCookieForPath(apkPath);
+            if (cookie == 0) {
+                throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
+                        "Failed adding asset path: " + apkPath);
+            }
+            parser = assets.openXmlResourceParser(cookie, PackageParser.ANDROID_MANIFEST_FILENAME);
+            final Resources res = new Resources(assets, displayMetrics, null);
+
+            ParseResult result = parseBaseApk(parseInput, separateProcesses, callback, apkPath, res,
+                    parser, flags);
+            if (!result.isSuccess()) {
+                throw new PackageParserException(result.getParseError(),
+                        apkPath + " (at " + parser.getPositionDescription() + "): "
+                                + result.getErrorMessage());
+            }
+
+            return result.getResultAndNull()
+                    .setVolumeUuid(volumeUuid)
+                    .setApplicationVolumeUuid(volumeUuid)
+                    .setSigningDetails(SigningDetails.UNKNOWN);
+        } catch (PackageParserException e) {
+            throw e;
+        } catch (Exception e) {
+            throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
+                    "Failed to read manifest from " + apkPath, e);
+        } finally {
+            IoUtils.closeQuietly(parser);
+        }
+    }
+
+    private static void parseSplitApk(
+            ParseInput parseInput,
+            DisplayMetrics displayMetrics,
+            String[] separateProcesses,
+            ParsingPackage parsingPackage,
+            int splitIndex,
+            AssetManager assets,
+            int flags
+    ) throws PackageParserException {
+        final String apkPath = parsingPackage.getSplitCodePaths()[splitIndex];
+
+        if (PackageParser.DEBUG_JAR) Slog.d(TAG, "Scanning split APK: " + apkPath);
+
+        final Resources res;
+        XmlResourceParser parser = null;
+        try {
+            // This must always succeed, as the path has been added to the AssetManager before.
+            final int cookie = assets.findCookieForPath(apkPath);
+            if (cookie == 0) {
+                throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
+                        "Failed adding asset path: " + apkPath);
+            }
+
+            parser = assets.openXmlResourceParser(cookie, PackageParser.ANDROID_MANIFEST_FILENAME);
+            res = new Resources(assets, displayMetrics, null);
+
+            final String[] outError = new String[1];
+            ParseResult parseResult = parseSplitApk(parseInput, separateProcesses, parsingPackage,
+                    res, parser, flags, splitIndex, outError);
+            if (!parseResult.isSuccess()) {
+                throw new PackageParserException(parseResult.getParseError(),
+                        apkPath + " (at " + parser.getPositionDescription() + "): "
+                                + parseResult.getErrorMessage());
+            }
+        } catch (PackageParserException e) {
+            throw e;
+        } catch (Exception e) {
+            throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
+                    "Failed to read manifest from " + apkPath, e);
+        } finally {
+            IoUtils.closeQuietly(parser);
+        }
+    }
+
+    /**
+     * Parse the manifest of a <em>base APK</em>. When adding new features you
+     * need to consider whether they should be supported by split APKs and child
+     * packages.
+     *
+     * @param apkPath  The package apk file path
+     * @param res      The resources from which to resolve values
+     * @param parser   The manifest parser
+     * @param flags    Flags how to parse
+     * @return Parsed package or null on error.
+     */
+    private static ParseResult parseBaseApk(
+            ParseInput parseInput,
+            String[] separateProcesses,
+            PackageParser.Callback callback,
+            String apkPath,
+            Resources res,
+            XmlResourceParser parser,
+            int flags
+    ) throws XmlPullParserException, IOException {
+        final String splitName;
+        final String pkgName;
+
+        try {
+            Pair<String, String> packageSplit = PackageParser.parsePackageSplitNames(parser,
+                    parser);
+            pkgName = packageSplit.first;
+            splitName = packageSplit.second;
+
+            if (!TextUtils.isEmpty(splitName)) {
+                return parseInput.error(
+                        PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
+                        "Expected base APK, but found split " + splitName
+                );
+            }
+        } catch (PackageParserException e) {
+            return parseInput.error(PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME);
+        }
+
+        // TODO: Remove when manifest overlaying removed
+        if (callback != null) {
+            String[] overlayPaths = callback.getOverlayPaths(pkgName, apkPath);
+            if (overlayPaths != null && overlayPaths.length > 0) {
+                for (String overlayPath : overlayPaths) {
+                    res.getAssets().addOverlayPath(overlayPath);
+                }
+            }
+        }
+
+        TypedArray manifestArray = null;
+
+        try {
+            manifestArray = res.obtainAttributes(parser, R.styleable.AndroidManifest);
+
+            boolean isCoreApp = parser.getAttributeBooleanValue(null, "coreApp", false);
+
+            ParsingPackage parsingPackage = PackageImpl.forParsing(
+                    pkgName,
+                    apkPath,
+                    manifestArray,
+                    isCoreApp
+            );
+
+            ParseResult result = parseBaseApkTags(parseInput, separateProcesses, callback,
+                    parsingPackage, manifestArray, res, parser, flags);
+            if (!result.isSuccess()) {
+                return result;
+            }
+
+            return parseInput.success(parsingPackage);
+        } finally {
+            if (manifestArray != null) {
+                manifestArray.recycle();
+            }
+        }
+    }
+
+    /**
+     * Parse the manifest of a <em>split APK</em>.
+     * <p>
+     * Note that split APKs have many more restrictions on what they're capable
+     * of doing, so many valid features of a base APK have been carefully
+     * omitted here.
+     *
+     * @param parsingPackage builder to fill
+     * @return false on failure
+     */
+    private static ParseResult parseSplitApk(
+            ParseInput parseInput,
+            String[] separateProcesses,
+            ParsingPackage parsingPackage,
+            Resources res,
+            XmlResourceParser parser,
+            int flags,
+            int splitIndex,
+            String[] outError
+    ) throws XmlPullParserException, IOException, PackageParserException {
+        AttributeSet attrs = parser;
+
+        // We parsed manifest tag earlier; just skip past it
+        PackageParser.parsePackageSplitNames(parser, attrs);
+
+        int type;
+
+        boolean foundApp = false;
+
+        int outerDepth = parser.getDepth();
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                continue;
+            }
+
+            String tagName = parser.getName();
+            if (tagName.equals(PackageParser.TAG_APPLICATION)) {
+                if (foundApp) {
+                    if (PackageParser.RIGID_PARSER) {
+                        return parseInput.error(
+                                PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                                "<manifest> has more than one <application>"
+                        );
+                    } else {
+                        Slog.w(TAG, "<manifest> has more than one <application>");
+                        XmlUtils.skipCurrentTag(parser);
+                        continue;
+                    }
+                }
+
+                foundApp = true;
+                ParseResult parseResult = parseSplitApplication(parseInput, separateProcesses,
+                        parsingPackage, res,
+                        parser, flags,
+                        splitIndex, outError);
+                if (!parseResult.isSuccess()) {
+                    return parseResult;
+                }
+
+            } else if (PackageParser.RIGID_PARSER) {
+                return parseInput.error(
+                        PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                        "Bad element under <manifest>: " + parser.getName()
+                );
+
+            } else {
+                Slog.w(TAG, "Unknown element under <manifest>: " + parser.getName()
+                        + " at " + parsingPackage.getBaseCodePath() + " "
+                        + parser.getPositionDescription());
+                XmlUtils.skipCurrentTag(parser);
+                continue;
+            }
+        }
+
+        if (!foundApp) {
+            return parseInput.error(
+                    PackageManager.INSTALL_PARSE_FAILED_MANIFEST_EMPTY,
+                    "<manifest> does not contain an <application>"
+            );
+        }
+
+        return parseInput.success(parsingPackage);
+    }
+
+    /**
+     * Parse the {@code application} XML tree at the current parse location in a
+     * <em>split APK</em> manifest.
+     * <p>
+     * Note that split APKs have many more restrictions on what they're capable
+     * of doing, so many valid features of a base APK have been carefully
+     * omitted here.
+     */
+    private static ParseResult parseSplitApplication(
+            ParseInput parseInput,
+            String[] separateProcesses,
+            ParsingPackage parsingPackage,
+            Resources res,
+            XmlResourceParser parser,
+            int flags,
+            int splitIndex,
+            String[] outError
+    ) throws XmlPullParserException, IOException {
+        TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestApplication);
+
+        parsingPackage.setSplitHasCode(splitIndex, sa.getBoolean(
+                R.styleable.AndroidManifestApplication_hasCode, true));
+
+        final String classLoaderName = sa.getString(
+                R.styleable.AndroidManifestApplication_classLoader);
+        if (classLoaderName == null || ClassLoaderFactory.isValidClassLoaderName(classLoaderName)) {
+            parsingPackage.setSplitClassLoaderName(splitIndex, classLoaderName);
+        } else {
+            return parseInput.error(
+                    PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                    "Invalid class loader name: " + classLoaderName
+            );
+        }
+
+        final int innerDepth = parser.getDepth();
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
+            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                continue;
+            }
+
+            ComponentParseUtils.ParsedComponent parsedComponent = null;
+
+            String tagName = parser.getName();
+            switch (tagName) {
+                case "activity":
+                    ComponentParseUtils.ParsedActivity activity =
+                            ComponentParseUtils.parseActivity(separateProcesses,
+                                    parsingPackage,
+                                    res, parser, flags,
+                                    outError,
+                                    false,
+                                    parsingPackage.isBaseHardwareAccelerated());
+                    if (activity == null) {
+                        return parseInput.error(
+                                PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                                outError[0]
+                        );
+                    }
+
+                    parsingPackage.addActivity(activity);
+                    parsedComponent = activity;
+                    break;
+                case "receiver":
+                    activity = ComponentParseUtils.parseActivity(
+                            separateProcesses, parsingPackage,
+                            res, parser, flags, outError,
+                            true, false);
+                    if (activity == null) {
+                        return parseInput.error(
+                                PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                                outError[0]
+                        );
+                    }
+
+                    parsingPackage.addReceiver(activity);
+                    parsedComponent = activity;
+                    break;
+                case "service":
+                    ComponentParseUtils.ParsedService s = ComponentParseUtils.parseService(
+                            separateProcesses,
+                            parsingPackage,
+                            res, parser, flags, outError
+                    );
+                    if (s == null) {
+                        return parseInput.error(
+                                PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                                outError[0]
+                        );
+                    }
+
+                    parsingPackage.addService(s);
+                    parsedComponent = s;
+                    break;
+                case "provider":
+                    ComponentParseUtils.ParsedProvider p = ComponentParseUtils.parseProvider(
+                            separateProcesses,
+                            parsingPackage,
+                            res, parser, flags, outError);
+                    if (p == null) {
+                        return parseInput.error(
+                                PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                                outError[0]
+                        );
+                    }
+
+                    parsingPackage.addProvider(p);
+                    parsedComponent = p;
+                    break;
+                case "activity-alias":
+                    activity = ComponentParseUtils.parseActivityAlias(
+                            parsingPackage,
+                            res,
+                            parser,
+                            outError
+                    );
+                    if (activity == null) {
+                        return parseInput.error(
+                                PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                                outError[0]
+                        );
+                    }
+
+                    parsingPackage.addActivity(activity);
+                    parsedComponent = activity;
+                    break;
+                case "meta-data":
+                    // note: application meta-data is stored off to the side, so it can
+                    // remain null in the primary copy (we like to avoid extra copies because
+                    // it can be large)
+                    Bundle appMetaData = parseMetaData(parsingPackage, res, parser,
+                            parsingPackage.getAppMetaData(),
+                            outError);
+                    if (appMetaData == null) {
+                        return parseInput.error(
+                                PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                                outError[0]
+                        );
+                    }
+
+                    parsingPackage.setAppMetaData(appMetaData);
+                    break;
+                case "uses-static-library":
+                    ParseResult parseResult = parseUsesStaticLibrary(parseInput, parsingPackage,
+                            res, parser);
+                    if (!parseResult.isSuccess()) {
+                        return parseResult;
+                    }
+
+                    break;
+                case "uses-library":
+                    sa = res.obtainAttributes(parser, R.styleable.AndroidManifestUsesLibrary);
+
+                    // Note: don't allow this value to be a reference to a resource
+                    // that may change.
+                    String lname = sa.getNonResourceString(
+                            R.styleable.AndroidManifestUsesLibrary_name);
+                    boolean req = sa.getBoolean(
+                            R.styleable.AndroidManifestUsesLibrary_required, true);
+
+                    sa.recycle();
+
+                    if (lname != null) {
+                        lname = lname.intern();
+                        if (req) {
+                            // Upgrade to treat as stronger constraint
+                            parsingPackage.addUsesLibrary(lname)
+                                    .removeUsesOptionalLibrary(lname);
+                        } else {
+                            // Ignore if someone already defined as required
+                            if (!ArrayUtils.contains(parsingPackage.getUsesLibraries(), lname)) {
+                                parsingPackage.addUsesOptionalLibrary(lname);
+                            }
+                        }
+                    }
+
+                    XmlUtils.skipCurrentTag(parser);
+                    break;
+                case "uses-package":
+                    // Dependencies for app installers; we don't currently try to
+                    // enforce this.
+                    XmlUtils.skipCurrentTag(parser);
+                    break;
+                default:
+                    if (!PackageParser.RIGID_PARSER) {
+                        Slog.w(TAG, "Unknown element under <application>: " + tagName
+                                + " at " + parsingPackage.getBaseCodePath() + " "
+                                + parser.getPositionDescription());
+                        XmlUtils.skipCurrentTag(parser);
+                        continue;
+                    } else {
+                        return parseInput.error(
+                                PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                                "Bad element under <application>: " + tagName
+                        );
+                    }
+            }
+
+            if (parsedComponent != null && parsedComponent.getSplitName() == null) {
+                // If the loaded component did not specify a split, inherit the split name
+                // based on the split it is defined in.
+                // This is used to later load the correct split when starting this
+                // component.
+                parsedComponent.setSplitName(parsingPackage.getSplitNames()[splitIndex]);
+            }
+        }
+
+        return parseInput.success(parsingPackage);
+    }
+
+    private static ParseResult parseBaseApkTags(
+            ParseInput parseInput,
+            String[] separateProcesses,
+            PackageParser.Callback callback,
+            ParsingPackage parsingPackage,
+            TypedArray manifestArray,
+            Resources res,
+            XmlResourceParser parser,
+            int flags
+    ) throws XmlPullParserException, IOException {
+        int type;
+        boolean foundApp = false;
+
+        TypedArray sa = manifestArray;
+
+        ParseResult sharedUserResult = parseSharedUser(parseInput, parsingPackage, sa);
+        if (!sharedUserResult.isSuccess()) {
+            return sharedUserResult;
+        }
+
+        parseManifestAttributes(sa, parsingPackage, flags);
+
+        int outerDepth = parser.getDepth();
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                continue;
+            }
+
+            String tagName = parser.getName();
+
+            // All methods return a boolean, even if they can't fail. This can be enforced
+            // by making this final and not assigned, forcing the switch to assign success
+            // once in every branch.
+            final boolean success;
+            ParseResult parseResult = null;
+
+            // TODO(b/135203078): Either use all booleans or all ParseResults
+            // TODO(b/135203078): Convert to instance methods to share variables
+            switch (tagName) {
+                case PackageParser.TAG_APPLICATION:
+                    if (foundApp) {
+                        if (PackageParser.RIGID_PARSER) {
+                            return parseInput.error(
+                                    PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                                    "<manifest> has more than one <application>"
+                            );
+                        } else {
+                            Slog.w(TAG, "<manifest> has more than one <application>");
+                            XmlUtils.skipCurrentTag(parser);
+                            success = true;
+                        }
+                    } else {
+                        foundApp = true;
+                        parseResult = parseBaseApplication(parseInput, separateProcesses,
+                                callback,
+                                parsingPackage, res, parser, flags);
+                        success = parseResult.isSuccess();
+                    }
+                    break;
+                case PackageParser.TAG_OVERLAY:
+                    parseResult = parseOverlay(parseInput, parsingPackage, res, parser);
+                    success = parseResult.isSuccess();
+                    break;
+                case PackageParser.TAG_KEY_SETS:
+                    parseResult = parseKeySets(parseInput, parsingPackage, res, parser);
+                    success = parseResult.isSuccess();
+                    break;
+                case PackageParser.TAG_PERMISSION_GROUP:
+                    parseResult = parsePermissionGroup(parseInput, parsingPackage, res,
+                            parser);
+                    success = parseResult.isSuccess();
+                    break;
+                case PackageParser.TAG_PERMISSION:
+                    parseResult = parsePermission(parseInput, parsingPackage, res, parser);
+                    success = parseResult.isSuccess();
+                    break;
+                case PackageParser.TAG_PERMISSION_TREE:
+                    parseResult = parsePermissionTree(parseInput, parsingPackage, res, parser);
+                    success = parseResult.isSuccess();
+                    break;
+                case PackageParser.TAG_USES_PERMISSION:
+                case PackageParser.TAG_USES_PERMISSION_SDK_M:
+                case PackageParser.TAG_USES_PERMISSION_SDK_23:
+                    parseResult = parseUsesPermission(parseInput, parsingPackage, res, parser,
+                            callback);
+                    success = parseResult.isSuccess();
+                    break;
+                case PackageParser.TAG_USES_CONFIGURATION:
+                    success = parseUsesConfiguration(parsingPackage, res, parser);
+                    break;
+                case PackageParser.TAG_USES_FEATURE:
+                    success = parseUsesFeature(parsingPackage, res, parser);
+                    break;
+                case PackageParser.TAG_FEATURE_GROUP:
+                    success = parseFeatureGroup(parsingPackage, res, parser);
+                    break;
+                case PackageParser.TAG_USES_SDK:
+                    parseResult = parseUsesSdk(parseInput, parsingPackage, res, parser);
+                    success = parseResult.isSuccess();
+                    break;
+                case PackageParser.TAG_SUPPORT_SCREENS:
+                    success = parseSupportScreens(parsingPackage, res, parser);
+                    break;
+                case PackageParser.TAG_PROTECTED_BROADCAST:
+                    success = parseProtectedBroadcast(parsingPackage, res, parser);
+                    break;
+                case PackageParser.TAG_INSTRUMENTATION:
+                    parseResult = parseInstrumentation(parseInput, parsingPackage, res,
+                            parser);
+                    success = parseResult.isSuccess();
+                    break;
+                case PackageParser.TAG_ORIGINAL_PACKAGE:
+                    success = parseOriginalPackage(parsingPackage, res, parser);
+                    break;
+                case PackageParser.TAG_ADOPT_PERMISSIONS:
+                    success = parseAdoptPermissions(parsingPackage, res, parser);
+                    break;
+                case PackageParser.TAG_USES_GL_TEXTURE:
+                case PackageParser.TAG_COMPATIBLE_SCREENS:
+                case PackageParser.TAG_SUPPORTS_INPUT:
+                case PackageParser.TAG_EAT_COMMENT:
+                    // Just skip this tag
+                    XmlUtils.skipCurrentTag(parser);
+                    success = true;
+                    break;
+                case PackageParser.TAG_RESTRICT_UPDATE:
+                    success = parseRestrictUpdateHash(flags, parsingPackage, res, parser);
+                    break;
+                case PackageParser.TAG_QUERIES:
+                    parseResult = parseQueries(parseInput, parsingPackage, res, parser);
+                    success = parseResult.isSuccess();
+                    break;
+                default:
+                    parseResult = parseUnknownTag(parseInput, parsingPackage, parser);
+                    success = parseResult.isSuccess();
+                    break;
+            }
+
+            if (parseResult != null && !parseResult.isSuccess()) {
+                return parseResult;
+            }
+
+            if (!success) {
+                return parseResult;
+            }
+        }
+
+        if (!foundApp && ArrayUtils.size(parsingPackage.getInstrumentations()) == 0) {
+            return parseInput.error(
+                    PackageManager.INSTALL_PARSE_FAILED_MANIFEST_EMPTY,
+                    "<manifest> does not contain an <application> or <instrumentation>"
+            );
+        }
+
+        convertNewPermissions(parsingPackage);
+
+        convertSplitPermissions(parsingPackage);
+
+        // At this point we can check if an application is not supporting densities and hence
+        // cannot be windowed / resized. Note that an SDK version of 0 is common for
+        // pre-Doughnut applications.
+        if (parsingPackage.usesCompatibilityMode()) {
+            adjustPackageToBeUnresizeableAndUnpipable(parsingPackage);
+        }
+
+        return parseInput.success(parsingPackage);
+    }
+
+    private static ParseResult parseUnknownTag(
+            ParseInput parseInput,
+            ParsingPackage parsingPackage,
+            XmlResourceParser parser
+    ) throws IOException, XmlPullParserException {
+        if (PackageParser.RIGID_PARSER) {
+            return parseInput.error(
+                    PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                    "Bad element under <manifest>: " + parser.getName()
+            );
+        } else {
+            Slog.w(TAG, "Unknown element under <manifest>: " + parser.getName()
+                    + " at " + parsingPackage.getBaseCodePath() + " "
+                    + parser.getPositionDescription());
+            XmlUtils.skipCurrentTag(parser);
+            return parseInput.success(parsingPackage);
+        }
+    }
+
+    private static ParseResult parseSharedUser(
+            ParseInput parseInput,
+            ParsingPackage parsingPackage,
+            TypedArray manifestArray
+    ) {
+        String str = manifestArray.getNonConfigurationString(
+                R.styleable.AndroidManifest_sharedUserId, 0);
+        if (TextUtils.isEmpty(str)) {
+            return parseInput.success(parsingPackage);
+        }
+
+        String nameError = validateName(str, true, true);
+        if (nameError != null && !"android".equals(parsingPackage.getPackageName())) {
+            return parseInput.error(
+                    PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID,
+                    "<manifest> specifies bad sharedUserId name \"" + str + "\": "
+                            + nameError
+            );
+        }
+
+        int sharedUserLabel = manifestArray.getResourceId(
+                R.styleable.AndroidManifest_sharedUserLabel, 0);
+        parsingPackage.setSharedUserId(str.intern())
+                .setSharedUserLabel(sharedUserLabel);
+
+        return parseInput.success(parsingPackage);
+    }
+
+    private static void parseManifestAttributes(
+            TypedArray manifestArray,
+            ParsingPackage parsingPackage,
+            int flags
+    ) {
+        int installLocation = manifestArray.getInteger(R.styleable.AndroidManifest_installLocation,
+                PackageParser.PARSE_DEFAULT_INSTALL_LOCATION);
+
+        final int targetSandboxVersion = manifestArray.getInteger(
+                R.styleable.AndroidManifest_targetSandboxVersion,
+                PackageParser.PARSE_DEFAULT_TARGET_SANDBOX);
+
+        parsingPackage.setInstallLocation(installLocation)
+                .setTargetSandboxVersion(targetSandboxVersion);
+
+        /* Set the global "on SD card" flag */
+        parsingPackage.setExternalStorage((flags & PackageParser.PARSE_EXTERNAL_STORAGE) != 0);
+
+        parsingPackage.setIsolatedSplitLoading(manifestArray.getBoolean(
+                R.styleable.AndroidManifest_isolatedSplits, false));
+    }
+
+    private static ParseResult parseKeySets(
+            ParseInput parseInput,
+            ParsingPackage parsingPackage,
+            Resources res,
+            XmlResourceParser parser
+    ) throws XmlPullParserException, IOException {
+        // we've encountered the 'key-sets' tag
+        // all the keys and keysets that we want must be defined here
+        // so we're going to iterate over the parser and pull out the things we want
+        int outerDepth = parser.getDepth();
+        int currentKeySetDepth = -1;
+        int type;
+        String currentKeySet = null;
+        ArrayMap<String, PublicKey> publicKeys = new ArrayMap<>();
+        ArraySet<String> upgradeKeySets = new ArraySet<>();
+        ArrayMap<String, ArraySet<String>> definedKeySets =
+                new ArrayMap<>();
+        ArraySet<String> improperKeySets = new ArraySet<>();
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+            if (type == XmlPullParser.END_TAG) {
+                if (parser.getDepth() == currentKeySetDepth) {
+                    currentKeySet = null;
+                    currentKeySetDepth = -1;
+                }
+                continue;
+            }
+            String tagName = parser.getName();
+            if (tagName.equals("key-set")) {
+                if (currentKeySet != null) {
+                    return parseInput.error(
+                            PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                            "Improperly nested 'key-set' tag at " + parser.getPositionDescription()
+                    );
+                }
+                final TypedArray sa = res.obtainAttributes(parser,
+                        R.styleable.AndroidManifestKeySet);
+                final String keysetName = sa.getNonResourceString(
+                        R.styleable.AndroidManifestKeySet_name);
+                definedKeySets.put(keysetName, new ArraySet<>());
+                currentKeySet = keysetName;
+                currentKeySetDepth = parser.getDepth();
+                sa.recycle();
+            } else if (tagName.equals("public-key")) {
+                if (currentKeySet == null) {
+                    return parseInput.error(
+                            PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                            "Improperly nested 'key-set' tag at " + parser.getPositionDescription()
+                    );
+                }
+                final TypedArray sa = res.obtainAttributes(parser,
+                        R.styleable.AndroidManifestPublicKey);
+                final String publicKeyName = sa.getNonResourceString(
+                        R.styleable.AndroidManifestPublicKey_name);
+                final String encodedKey = sa.getNonResourceString(
+                        R.styleable.AndroidManifestPublicKey_value);
+                if (encodedKey == null && publicKeys.get(publicKeyName) == null) {
+                    sa.recycle();
+                    return parseInput.error(
+                            PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                            "'public-key' " + publicKeyName + " must define a public-key value"
+                                    + " on first use at " + parser.getPositionDescription()
+                    );
+                } else if (encodedKey != null) {
+                    PublicKey currentKey = PackageParser.parsePublicKey(encodedKey);
+                    if (currentKey == null) {
+                        Slog.w(TAG, "No recognized valid key in 'public-key' tag at "
+                                + parser.getPositionDescription() + " key-set " + currentKeySet
+                                + " will not be added to the package's defined key-sets.");
+                        sa.recycle();
+                        improperKeySets.add(currentKeySet);
+                        XmlUtils.skipCurrentTag(parser);
+                        continue;
+                    }
+                    if (publicKeys.get(publicKeyName) == null
+                            || publicKeys.get(publicKeyName).equals(currentKey)) {
+
+                        /* public-key first definition, or matches old definition */
+                        publicKeys.put(publicKeyName, currentKey);
+                    } else {
+                        sa.recycle();
+                        return parseInput.error(
+                                PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                                "Value of 'public-key' " + publicKeyName
+                                        + " conflicts with previously defined value at "
+                                        + parser.getPositionDescription()
+                        );
+                    }
+                }
+                definedKeySets.get(currentKeySet).add(publicKeyName);
+                sa.recycle();
+                XmlUtils.skipCurrentTag(parser);
+            } else if (tagName.equals("upgrade-key-set")) {
+                final TypedArray sa = res.obtainAttributes(parser,
+                        R.styleable.AndroidManifestUpgradeKeySet);
+                String name = sa.getNonResourceString(
+                        R.styleable.AndroidManifestUpgradeKeySet_name);
+                upgradeKeySets.add(name);
+                sa.recycle();
+                XmlUtils.skipCurrentTag(parser);
+            } else if (PackageParser.RIGID_PARSER) {
+                return parseInput.error(
+                        PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                        "Bad element under <key-sets>: " + parser.getName()
+                                + " at " + parsingPackage.getBaseCodePath() + " "
+                                + parser.getPositionDescription()
+                );
+            } else {
+                Slog.w(TAG, "Unknown element under <key-sets>: " + parser.getName()
+                        + " at " + parsingPackage.getBaseCodePath() + " "
+                        + parser.getPositionDescription());
+                XmlUtils.skipCurrentTag(parser);
+                continue;
+            }
+        }
+        String packageName = parsingPackage.getPackageName();
+        Set<String> publicKeyNames = publicKeys.keySet();
+        if (publicKeyNames.removeAll(definedKeySets.keySet())) {
+            return parseInput.error(
+                    PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                    "Package" + packageName + " AndroidManifest.xml "
+                            + "'key-set' and 'public-key' names must be distinct."
+            );
+        }
+
+        for (ArrayMap.Entry<String, ArraySet<String>> e : definedKeySets.entrySet()) {
+            final String keySetName = e.getKey();
+            if (e.getValue().size() == 0) {
+                Slog.w(TAG, "Package" + packageName + " AndroidManifest.xml "
+                        + "'key-set' " + keySetName + " has no valid associated 'public-key'."
+                        + " Not including in package's defined key-sets.");
+                continue;
+            } else if (improperKeySets.contains(keySetName)) {
+                Slog.w(TAG, "Package" + packageName + " AndroidManifest.xml "
+                        + "'key-set' " + keySetName + " contained improper 'public-key'"
+                        + " tags. Not including in package's defined key-sets.");
+                continue;
+            }
+
+            for (String s : e.getValue()) {
+                parsingPackage.addKeySet(keySetName, publicKeys.get(s));
+            }
+        }
+        if (parsingPackage.getKeySetMapping().keySet().containsAll(upgradeKeySets)) {
+            parsingPackage.setUpgradeKeySets(upgradeKeySets);
+        } else {
+            return parseInput.error(
+                    PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                    "Package" + packageName + " AndroidManifest.xml "
+                            + "does not define all 'upgrade-key-set's ."
+            );
+        }
+
+        return parseInput.success(parsingPackage);
+    }
+
+    public static boolean parsePackageItemInfo(String packageName, PackageItemInfo outInfo,
+            String[] outError, String tag, TypedArray sa, boolean nameRequired,
+            int nameRes, int labelRes, int iconRes, int roundIconRes, int logoRes, int bannerRes) {
+        // This case can only happen in unit tests where we sometimes need to create fakes
+        // of various package parser data structures.
+        if (sa == null) {
+            outError[0] = tag + " does not contain any attributes";
+            return false;
+        }
+
+        String name = sa.getNonConfigurationString(nameRes, 0);
+        if (name == null) {
+            if (nameRequired) {
+                outError[0] = tag + " does not specify android:name";
+                return false;
+            }
+        } else {
+            String outInfoName = buildClassName(packageName, name);
+            if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(outInfoName)) {
+                outError[0] = tag + " invalid android:name";
+                return false;
+            }
+            outInfo.name = outInfoName;
+            if (outInfoName == null) {
+                return false;
+            }
+        }
+
+        int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId(roundIconRes, 0) : 0;
+        if (roundIconVal != 0) {
+            outInfo.icon = roundIconVal;
+            outInfo.nonLocalizedLabel = null;
+        } else {
+            int iconVal = sa.getResourceId(iconRes, 0);
+            if (iconVal != 0) {
+                outInfo.icon = iconVal;
+                outInfo.nonLocalizedLabel = null;
+            }
+        }
+
+        int logoVal = sa.getResourceId(logoRes, 0);
+        if (logoVal != 0) {
+            outInfo.logo = logoVal;
+        }
+
+        int bannerVal = sa.getResourceId(bannerRes, 0);
+        if (bannerVal != 0) {
+            outInfo.banner = bannerVal;
+        }
+
+        TypedValue v = sa.peekValue(labelRes);
+        if (v != null && (outInfo.labelRes = v.resourceId) == 0) {
+            outInfo.nonLocalizedLabel = v.coerceToString();
+        }
+
+        outInfo.packageName = packageName;
+
+        return true;
+    }
+
+    private static ParseResult parsePackageItemInfo(
+            ParseInput parseInput,
+            ParsingPackage parsingPackage,
+            String tag,
+            TypedArray sa,
+            boolean nameRequired,
+            int nameRes,
+            int labelRes,
+            int iconRes,
+            int roundIconRes,
+            int logoRes,
+            int bannerRes
+    ) {
+        // This case can only happen in unit tests where we sometimes need to create fakes
+        // of various package parser data structures.
+        if (sa == null) {
+            return parseInput.error(
+                    PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                    tag + " does not contain any attributes"
+            );
+        }
+
+        String name = sa.getNonConfigurationString(nameRes, 0);
+        if (name == null) {
+            if (nameRequired) {
+                return parseInput.error(
+                        PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                        tag + " does not specify android:name"
+                );
+            }
+        } else {
+            String packageName = parsingPackage.getPackageName();
+            String outInfoName = buildClassName(packageName, name);
+            if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(outInfoName)) {
+                return parseInput.error(
+                        PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                        tag + " invalid android:name"
+                );
+            } else if (outInfoName == null) {
+                return parseInput.error(
+                        PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                        "Empty class name in package " + packageName
+                );
+            }
+
+            parsingPackage.setName(outInfoName);
+        }
+
+        int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId(roundIconRes, 0) : 0;
+        if (roundIconVal != 0) {
+            parsingPackage.setIcon(roundIconVal)
+                    .setNonLocalizedLabel(null);
+        } else {
+            int iconVal = sa.getResourceId(iconRes, 0);
+            if (iconVal != 0) {
+                parsingPackage.setIcon(iconVal)
+                        .setNonLocalizedLabel(null);
+            }
+        }
+
+        int logoVal = sa.getResourceId(logoRes, 0);
+        if (logoVal != 0) {
+            parsingPackage.setLogo(logoVal);
+        }
+
+        int bannerVal = sa.getResourceId(bannerRes, 0);
+        if (bannerVal != 0) {
+            parsingPackage.setBanner(bannerVal);
+        }
+
+        TypedValue v = sa.peekValue(labelRes);
+        if (v != null) {
+            parsingPackage.setLabelRes(v.resourceId);
+            if (v.resourceId == 0) {
+                parsingPackage.setNonLocalizedLabel(v.coerceToString());
+            }
+        }
+
+        return parseInput.success(parsingPackage);
+    }
+
+    private static ParseResult parsePermissionGroup(
+            ParseInput parseInput,
+            ParsingPackage parsingPackage,
+            Resources res,
+            XmlResourceParser parser
+    ) throws XmlPullParserException, IOException {
+        // TODO(b/135203078): Remove, replace with ParseResult
+        String[] outError = new String[1];
+
+        ComponentParseUtils.ParsedPermissionGroup parsedPermissionGroup =
+                ComponentParseUtils.parsePermissionGroup(parsingPackage,
+                        res, parser, outError);
+
+        if (parsedPermissionGroup == null || outError[0] != null) {
+            return parseInput.error(
+                    PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                    outError[0]
+            );
+        }
+
+        parsingPackage.addPermissionGroup(parsedPermissionGroup);
+
+        return parseInput.success(parsingPackage);
+    }
+
+    private static ParseResult parsePermission(
+            ParseInput parseInput,
+            ParsingPackage parsingPackage,
+            Resources res,
+            XmlResourceParser parser
+    ) throws XmlPullParserException, IOException {
+        // TODO(b/135203078): Remove, replace with ParseResult
+        String[] outError = new String[1];
+
+        ComponentParseUtils.ParsedPermission parsedPermission =
+                ComponentParseUtils.parsePermission(parsingPackage,
+                        res, parser, outError);
+
+        if (parsedPermission == null || outError[0] != null) {
+            return parseInput.error(
+                    PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                    outError[0]
+            );
+        }
+
+        parsingPackage.addPermission(parsedPermission);
+
+        return parseInput.success(parsingPackage);
+    }
+
+    private static ParseResult parsePermissionTree(
+            ParseInput parseInput,
+            ParsingPackage parsingPackage,
+            Resources res,
+            XmlResourceParser parser
+    ) throws XmlPullParserException, IOException {
+        // TODO(b/135203078): Remove, replace with ParseResult
+        String[] outError = new String[1];
+
+        ComponentParseUtils.ParsedPermission parsedPermission =
+                ComponentParseUtils.parsePermissionTree(parsingPackage,
+                        res, parser, outError);
+
+        if (parsedPermission == null || outError[0] != null) {
+            return parseInput.error(
+                    PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                    outError[0]
+            );
+        }
+
+        parsingPackage.addPermission(parsedPermission);
+
+        return parseInput.success(parsingPackage);
+    }
+
+    private static ParseResult parseUsesPermission(
+            ParseInput parseInput,
+            ParsingPackage parsingPackage,
+            Resources res,
+            XmlResourceParser parser,
+            PackageParser.Callback callback
+    )
+            throws XmlPullParserException, IOException {
+        TypedArray sa = res.obtainAttributes(parser,
+                R.styleable.AndroidManifestUsesPermission);
+
+        // Note: don't allow this value to be a reference to a resource
+        // that may change.
+        String name = sa.getNonResourceString(
+                R.styleable.AndroidManifestUsesPermission_name);
+
+        int maxSdkVersion = 0;
+        TypedValue val = sa.peekValue(
+                R.styleable.AndroidManifestUsesPermission_maxSdkVersion);
+        if (val != null) {
+            if (val.type >= TypedValue.TYPE_FIRST_INT && val.type <= TypedValue.TYPE_LAST_INT) {
+                maxSdkVersion = val.data;
+            }
+        }
+
+        final String requiredFeature = sa.getNonConfigurationString(
+                R.styleable.AndroidManifestUsesPermission_requiredFeature, 0);
+
+        final String requiredNotfeature = sa.getNonConfigurationString(
+                R.styleable.AndroidManifestUsesPermission_requiredNotFeature,
+                0);
+
+        sa.recycle();
+
+        XmlUtils.skipCurrentTag(parser);
+
+        // Can only succeed from here on out
+        ParseResult success = parseInput.success(parsingPackage);
+
+        if (name == null) {
+            return success;
+        }
+
+        if ((maxSdkVersion != 0) && (maxSdkVersion < Build.VERSION.RESOURCES_SDK_INT)) {
+            return success;
+        }
+
+        // Only allow requesting this permission if the platform supports the given feature.
+        if (requiredFeature != null && callback != null && !callback.hasFeature(requiredFeature)) {
+            return success;
+        }
+
+        // Only allow requesting this permission if the platform doesn't support the given feature.
+        if (requiredNotfeature != null && callback != null
+                && callback.hasFeature(requiredNotfeature)) {
+            return success;
+        }
+
+        if (!parsingPackage.getRequestedPermissions().contains(name)) {
+            parsingPackage.addRequestedPermission(name.intern());
+        } else {
+            Slog.w(TAG, "Ignoring duplicate uses-permissions/uses-permissions-sdk-m: "
+                    + name + " in package: " + parsingPackage.getPackageName() + " at: "
+                    + parser.getPositionDescription());
+        }
+
+        return success;
+    }
+
+    private static boolean parseUsesConfiguration(
+            ParsingPackage parsingPackage,
+            Resources res,
+            XmlResourceParser parser
+    ) throws IOException, XmlPullParserException {
+        ConfigurationInfo cPref = new ConfigurationInfo();
+        TypedArray sa = res.obtainAttributes(parser,
+                R.styleable.AndroidManifestUsesConfiguration);
+        cPref.reqTouchScreen = sa.getInt(
+                R.styleable.AndroidManifestUsesConfiguration_reqTouchScreen,
+                Configuration.TOUCHSCREEN_UNDEFINED);
+        cPref.reqKeyboardType = sa.getInt(
+                R.styleable.AndroidManifestUsesConfiguration_reqKeyboardType,
+                Configuration.KEYBOARD_UNDEFINED);
+        if (sa.getBoolean(
+                R.styleable.AndroidManifestUsesConfiguration_reqHardKeyboard,
+                false)) {
+            cPref.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
+        }
+        cPref.reqNavigation = sa.getInt(
+                R.styleable.AndroidManifestUsesConfiguration_reqNavigation,
+                Configuration.NAVIGATION_UNDEFINED);
+        if (sa.getBoolean(
+                R.styleable.AndroidManifestUsesConfiguration_reqFiveWayNav,
+                false)) {
+            cPref.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
+        }
+        sa.recycle();
+        parsingPackage.addConfigPreference(cPref);
+
+        XmlUtils.skipCurrentTag(parser);
+        return true;
+    }
+
+    private static boolean parseUsesFeature(
+            ParsingPackage parsingPackage,
+            Resources res,
+            XmlResourceParser parser
+    ) throws IOException, XmlPullParserException {
+        FeatureInfo fi = parseFeatureInfo(res, parser);
+        parsingPackage.addReqFeature(fi);
+
+        if (fi.name == null) {
+            ConfigurationInfo cPref = new ConfigurationInfo();
+            cPref.reqGlEsVersion = fi.reqGlEsVersion;
+            parsingPackage.addConfigPreference(cPref);
+        }
+
+        XmlUtils.skipCurrentTag(parser);
+        return true;
+    }
+
+    private static FeatureInfo parseFeatureInfo(Resources res, AttributeSet attrs) {
+        FeatureInfo fi = new FeatureInfo();
+        TypedArray sa = res.obtainAttributes(attrs,
+                R.styleable.AndroidManifestUsesFeature);
+        // Note: don't allow this value to be a reference to a resource
+        // that may change.
+        fi.name = sa.getNonResourceString(R.styleable.AndroidManifestUsesFeature_name);
+        fi.version = sa.getInt(R.styleable.AndroidManifestUsesFeature_version, 0);
+        if (fi.name == null) {
+            fi.reqGlEsVersion = sa.getInt(R.styleable.AndroidManifestUsesFeature_glEsVersion,
+                    FeatureInfo.GL_ES_VERSION_UNDEFINED);
+        }
+        if (sa.getBoolean(R.styleable.AndroidManifestUsesFeature_required, true)) {
+            fi.flags |= FeatureInfo.FLAG_REQUIRED;
+        }
+        sa.recycle();
+        return fi;
+    }
+
+    private static boolean parseFeatureGroup(
+            ParsingPackage parsingPackage,
+            Resources res,
+            XmlResourceParser parser
+    ) throws IOException, XmlPullParserException {
+        FeatureGroupInfo group = new FeatureGroupInfo();
+        ArrayList<FeatureInfo> features = null;
+        final int innerDepth = parser.getDepth();
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG
+                || parser.getDepth() > innerDepth)) {
+            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                continue;
+            }
+
+            final String innerTagName = parser.getName();
+            if (innerTagName.equals("uses-feature")) {
+                FeatureInfo featureInfo = parseFeatureInfo(res, parser);
+                // FeatureGroups are stricter and mandate that
+                // any <uses-feature> declared are mandatory.
+                featureInfo.flags |= FeatureInfo.FLAG_REQUIRED;
+                features = ArrayUtils.add(features, featureInfo);
+            } else {
+                Slog.w(TAG,
+                        "Unknown element under <feature-group>: " + innerTagName +
+                                " at " + parsingPackage.getBaseCodePath() + " " +
+                                parser.getPositionDescription());
+            }
+            XmlUtils.skipCurrentTag(parser);
+        }
+
+        if (features != null) {
+            group.features = new FeatureInfo[features.size()];
+            group.features = features.toArray(group.features);
+        }
+
+        parsingPackage.addFeatureGroup(group);
+        return true;
+    }
+
+    private static ParseResult parseUsesSdk(
+            ParseInput parseInput,
+            ParsingPackage parsingPackage,
+            Resources res,
+            XmlResourceParser parser
+    ) throws IOException, XmlPullParserException {
+        if (PackageParser.SDK_VERSION > 0) {
+            TypedArray sa = res.obtainAttributes(parser,
+                    R.styleable.AndroidManifestUsesSdk);
+
+            int minVers = 1;
+            String minCode = null;
+            int targetVers = 0;
+            String targetCode = null;
+
+            TypedValue val = sa.peekValue(R.styleable.AndroidManifestUsesSdk_minSdkVersion);
+            if (val != null) {
+                if (val.type == TypedValue.TYPE_STRING && val.string != null) {
+                    minCode = val.string.toString();
+                } else {
+                    // If it's not a string, it's an integer.
+                    minVers = val.data;
+                }
+            }
+
+            val = sa.peekValue(R.styleable.AndroidManifestUsesSdk_targetSdkVersion);
+            if (val != null) {
+                if (val.type == TypedValue.TYPE_STRING && val.string != null) {
+                    targetCode = val.string.toString();
+                    if (minCode == null) {
+                        minCode = targetCode;
+                    }
+                } else {
+                    // If it's not a string, it's an integer.
+                    targetVers = val.data;
+                }
+            } else {
+                targetVers = minVers;
+                targetCode = minCode;
+            }
+
+            sa.recycle();
+
+            // TODO(b/135203078): Remove, replace with ParseResult
+            String[] outError = new String[1];
+            final int minSdkVersion = PackageParser.computeMinSdkVersion(minVers,
+                    minCode,
+                    PackageParser.SDK_VERSION, PackageParser.SDK_CODENAMES, outError);
+            if (minSdkVersion < 0) {
+                return parseInput.error(
+                        PackageManager.INSTALL_FAILED_OLDER_SDK
+                );
+            }
+
+            final int targetSdkVersion = PackageParser.computeTargetSdkVersion(
+                    targetVers,
+                    targetCode, PackageParser.SDK_CODENAMES, outError);
+            if (targetSdkVersion < 0) {
+                return parseInput.error(
+                        PackageManager.INSTALL_FAILED_OLDER_SDK
+                );
+            }
+
+            parsingPackage.setMinSdkVersion(minSdkVersion)
+                    .setTargetSdkVersion(targetSdkVersion);
+        }
+
+        XmlUtils.skipCurrentTag(parser);
+        return parseInput.success(parsingPackage);
+    }
+
+    private static boolean parseRestrictUpdateHash(
+            int flags,
+            ParsingPackage parsingPackage,
+            Resources res,
+            XmlResourceParser parser
+    ) throws IOException, XmlPullParserException {
+        if ((flags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0) {
+            TypedArray sa = res.obtainAttributes(parser,
+                    R.styleable.AndroidManifestRestrictUpdate);
+            final String hash = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestRestrictUpdate_hash,
+                    0);
+            sa.recycle();
+
+            if (hash != null) {
+                final int hashLength = hash.length();
+                final byte[] hashBytes = new byte[hashLength / 2];
+                for (int i = 0; i < hashLength; i += 2) {
+                    hashBytes[i / 2] = (byte) ((Character.digit(hash.charAt(i), 16)
+                            << 4)
+                            + Character.digit(hash.charAt(i + 1), 16));
+                }
+                parsingPackage.setRestrictUpdateHash(hashBytes);
+            } else {
+                parsingPackage.setRestrictUpdateHash(null);
+            }
+        }
+
+        XmlUtils.skipCurrentTag(parser);
+        return true;
+    }
+
+    private static ParseResult parseQueries(
+            ParseInput parseInput,
+            ParsingPackage parsingPackage,
+            Resources res,
+            XmlResourceParser parser
+    ) throws IOException, XmlPullParserException {
+
+        final int outerDepth = parser.getDepth();
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG
+                || parser.getDepth() > outerDepth)) {
+            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                continue;
+            }
+            if (parser.getName().equals("intent")) {
+                String[] outError = new String[1];
+                ComponentParseUtils.ParsedQueriesIntentInfo intentInfo =
+                        ComponentParseUtils.parsedParsedQueriesIntentInfo(
+                                parsingPackage, res, parser, outError
+                        );
+                if (intentInfo == null) {
+                    return parseInput.error(
+                            PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                            outError[0]
+                    );
+                }
+
+                Uri data = null;
+                String dataType = null;
+                String host = "";
+                final int numActions = intentInfo.countActions();
+                final int numSchemes = intentInfo.countDataSchemes();
+                final int numTypes = intentInfo.countDataTypes();
+                final int numHosts = intentInfo.getHosts().length;
+                if ((numSchemes == 0 && numTypes == 0 && numActions == 0)) {
+                    outError[0] = "intent tags must contain either an action or data.";
+                    return parseInput.error(
+                            PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                            outError[0]
+                    );
+                }
+                if (numActions > 1) {
+                    outError[0] = "intent tag may have at most one action.";
+                    return parseInput.error(
+                            PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                            outError[0]
+                    );
+                }
+                if (numTypes > 1) {
+                    outError[0] = "intent tag may have at most one data type.";
+                    return parseInput.error(
+                            PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                            outError[0]
+                    );
+                }
+                if (numSchemes > 1) {
+                    outError[0] = "intent tag may have at most one data scheme.";
+                    return parseInput.error(
+                            PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                            outError[0]
+                    );
+                }
+                if (numHosts > 1) {
+                    outError[0] = "intent tag may have at most one data host.";
+                    return parseInput.error(
+                            PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                            outError[0]
+                    );
+                }
+                Intent intent = new Intent();
+                for (int i = 0, max = intentInfo.countCategories(); i < max; i++) {
+                    intent.addCategory(intentInfo.getCategory(i));
+                }
+                if (numHosts == 1) {
+                    host = intentInfo.getHosts()[0];
+                }
+                if (numSchemes == 1) {
+                    data = new Uri.Builder()
+                            .scheme(intentInfo.getDataScheme(0))
+                            .authority(host)
+                            .build();
+                }
+                if (numTypes == 1) {
+                    dataType = intentInfo.getDataType(0);
+                }
+                intent.setDataAndType(data, dataType);
+                if (numActions == 1) {
+                    intent.setAction(intentInfo.getAction(0));
+                }
+                parsingPackage.addQueriesIntent(intent);
+            } else if (parser.getName().equals("package")) {
+                final TypedArray sa = res.obtainAttributes(parser,
+                        R.styleable.AndroidManifestQueriesPackage);
+                final String packageName =
+                        sa.getString(R.styleable.AndroidManifestQueriesPackage_name);
+                if (TextUtils.isEmpty(packageName)) {
+                    return parseInput.error(
+                            PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                            "Package name is missing from package tag."
+                    );
+                }
+                parsingPackage.addQueriesPackage(packageName.intern());
+            }
+        }
+        return parseInput.success(parsingPackage);
+    }
+
+    /**
+     * Parse the {@code application} XML tree at the current parse location in a
+     * <em>base APK</em> manifest.
+     * <p>
+     * When adding new features, carefully consider if they should also be
+     * supported by split APKs.
+     *
+     * @hide
+     */
+    public static ParseResult parseBaseApplication(
+            ParseInput parseInput,
+            String[] separateProcesses,
+            PackageParser.Callback callback,
+            ParsingPackage parsingPackage,
+            Resources res,
+            XmlResourceParser parser,
+            int flags
+    ) throws XmlPullParserException, IOException {
+        final String pkgName = parsingPackage.getPackageName();
+
+        // TODO(b/135203078): Remove, replace with ParseResult
+        String[] outError = new String[1];
+        TypedArray sa = null;
+
+        try {
+            sa = res.obtainAttributes(parser,
+                    R.styleable.AndroidManifestApplication);
+
+
+            parsingPackage
+                    .setIconRes(
+                            sa.getResourceId(R.styleable.AndroidManifestApplication_icon, 0))
+                    .setRoundIconRes(
+                            sa.getResourceId(R.styleable.AndroidManifestApplication_roundIcon, 0));
+
+            ParseResult result = parsePackageItemInfo(
+                    parseInput,
+                    parsingPackage,
+                    "<application>",
+                    sa, false /*nameRequired*/,
+                    R.styleable.AndroidManifestApplication_name,
+                    R.styleable.AndroidManifestApplication_label,
+                    R.styleable.AndroidManifestApplication_icon,
+                    R.styleable.AndroidManifestApplication_roundIcon,
+                    R.styleable.AndroidManifestApplication_logo,
+                    R.styleable.AndroidManifestApplication_banner
+            );
+            if (!result.isSuccess()) {
+                return result;
+            }
+
+            String name = parsingPackage.getName();
+            if (name != null) {
+                parsingPackage.setClassName(name);
+            }
+
+            String manageSpaceActivity = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestApplication_manageSpaceActivity,
+                    Configuration.NATIVE_CONFIG_VERSION);
+            if (manageSpaceActivity != null) {
+                String manageSpaceActivityName = buildClassName(pkgName, manageSpaceActivity);
+
+                if (manageSpaceActivityName == null) {
+                    return parseInput.error(
+                            PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                            "Empty class name in package " + pkgName
+                    );
+                }
+
+                parsingPackage.setManageSpaceActivityName(manageSpaceActivityName);
+            }
+
+            boolean allowBackup = sa.getBoolean(
+                    R.styleable.AndroidManifestApplication_allowBackup, true);
+            parsingPackage.setAllowBackup(allowBackup);
+
+            if (allowBackup) {
+                // backupAgent, killAfterRestore, fullBackupContent, backupInForeground,
+                // and restoreAnyVersion are only relevant if backup is possible for the
+                // given application.
+                String backupAgent = sa.getNonConfigurationString(
+                        R.styleable.AndroidManifestApplication_backupAgent,
+                        Configuration.NATIVE_CONFIG_VERSION);
+                if (backupAgent != null) {
+                    String backupAgentName = buildClassName(pkgName, backupAgent);
+                    if (backupAgentName == null) {
+                        return parseInput.error(
+                                PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                                "Empty class name in package " + pkgName
+                        );
+                    }
+
+                    if (PackageParser.DEBUG_BACKUP) {
+                        Slog.v(TAG, "android:backupAgent = " + backupAgentName
+                                + " from " + pkgName + "+" + backupAgent);
+                    }
+
+                    parsingPackage.setBackupAgentName(backupAgentName);
+
+                    parsingPackage.setKillAfterRestore(sa.getBoolean(
+                            R.styleable.AndroidManifestApplication_killAfterRestore, true));
+
+                    parsingPackage.setRestoreAnyVersion(sa.getBoolean(
+                            R.styleable.AndroidManifestApplication_restoreAnyVersion, false));
+
+                    parsingPackage.setFullBackupOnly(sa.getBoolean(
+                            R.styleable.AndroidManifestApplication_fullBackupOnly, false));
+
+                    parsingPackage.setBackupInForeground(sa.getBoolean(
+                            R.styleable.AndroidManifestApplication_backupInForeground,
+                            false));
+                }
+
+                TypedValue v = sa.peekValue(
+                        R.styleable.AndroidManifestApplication_fullBackupContent);
+                int fullBackupContent = 0;
+
+                if (v != null) {
+                    fullBackupContent = v.resourceId;
+
+                    if (v.resourceId == 0) {
+                        if (PackageParser.DEBUG_BACKUP) {
+                            Slog.v(TAG, "fullBackupContent specified as boolean=" +
+                                    (v.data == 0 ? "false" : "true"));
+                        }
+                        // "false" => -1, "true" => 0
+                        fullBackupContent = v.data == 0 ? -1 : 0;
+                    }
+
+                    parsingPackage.setFullBackupContent(fullBackupContent);
+                }
+                if (PackageParser.DEBUG_BACKUP) {
+                    Slog.v(TAG, "fullBackupContent=" + fullBackupContent + " for " + pkgName);
+                }
+            }
+
+            parsingPackage
+                    .setTheme(
+                            sa.getResourceId(R.styleable.AndroidManifestApplication_theme, 0))
+                    .setDescriptionRes(
+                            sa.getResourceId(R.styleable.AndroidManifestApplication_description,
+                                    0));
+
+            if (sa.getBoolean(
+                    R.styleable.AndroidManifestApplication_persistent,
+                    false)) {
+                // Check if persistence is based on a feature being present
+                final String requiredFeature = sa.getNonResourceString(R.styleable
+                        .AndroidManifestApplication_persistentWhenFeatureAvailable);
+                parsingPackage.setPersistent(requiredFeature == null
+                        || callback.hasFeature(requiredFeature));
+            }
+
+            boolean requiredForAllUsers = sa.getBoolean(
+                    R.styleable.AndroidManifestApplication_requiredForAllUsers,
+                    false);
+            parsingPackage.setRequiredForAllUsers(requiredForAllUsers);
+
+            String restrictedAccountType = sa.getString(R.styleable
+                    .AndroidManifestApplication_restrictedAccountType);
+            if (restrictedAccountType != null && restrictedAccountType.length() > 0) {
+                parsingPackage.setRestrictedAccountType(restrictedAccountType);
+            }
+
+            String requiredAccountType = sa.getString(R.styleable
+                    .AndroidManifestApplication_requiredAccountType);
+            if (requiredAccountType != null && requiredAccountType.length() > 0) {
+                parsingPackage.setRequiredAccountType(requiredAccountType);
+            }
+
+            parsingPackage.setForceQueryable(
+                    sa.getBoolean(R.styleable.AndroidManifestApplication_forceQueryable, false)
+            );
+
+            boolean debuggable = sa.getBoolean(
+                    R.styleable.AndroidManifestApplication_debuggable,
+                    false
+            );
+
+            parsingPackage.setDebuggable(debuggable);
+
+            if (debuggable) {
+                // Debuggable implies profileable
+                parsingPackage.setProfileableByShell(true);
+            }
+
+            parsingPackage.setVmSafeMode(sa.getBoolean(
+                    R.styleable.AndroidManifestApplication_vmSafeMode, false));
+
+            boolean baseHardwareAccelerated = sa.getBoolean(
+                    R.styleable.AndroidManifestApplication_hardwareAccelerated,
+                    parsingPackage.getTargetSdkVersion()
+                            >= Build.VERSION_CODES.ICE_CREAM_SANDWICH);
+            parsingPackage.setBaseHardwareAccelerated(baseHardwareAccelerated);
+
+            parsingPackage.setHasCode(sa.getBoolean(
+                    R.styleable.AndroidManifestApplication_hasCode, true));
+
+            parsingPackage.setAllowTaskReparenting(sa.getBoolean(
+                    R.styleable.AndroidManifestApplication_allowTaskReparenting, false));
+
+            parsingPackage.setAllowClearUserData(sa.getBoolean(
+                    R.styleable.AndroidManifestApplication_allowClearUserData, true));
+
+            parsingPackage.setTestOnly(sa.getBoolean(
+                    com.android.internal.R.styleable.AndroidManifestApplication_testOnly,
+                    false));
+
+            parsingPackage.setLargeHeap(sa.getBoolean(
+                    R.styleable.AndroidManifestApplication_largeHeap, false));
+
+            parsingPackage.setUsesCleartextTraffic(sa.getBoolean(
+                    R.styleable.AndroidManifestApplication_usesCleartextTraffic,
+                    parsingPackage.getTargetSdkVersion() < Build.VERSION_CODES.P));
+
+            parsingPackage.setSupportsRtl(sa.getBoolean(
+                    R.styleable.AndroidManifestApplication_supportsRtl,
+                    false /* default is no RTL support*/));
+
+            parsingPackage.setMultiArch(sa.getBoolean(
+                    R.styleable.AndroidManifestApplication_multiArch, false));
+
+            parsingPackage.setExtractNativeLibs(sa.getBoolean(
+                    R.styleable.AndroidManifestApplication_extractNativeLibs, true));
+
+            parsingPackage.setUseEmbeddedDex(sa.getBoolean(
+                    R.styleable.AndroidManifestApplication_useEmbeddedDex, false));
+
+            parsingPackage.setDefaultToDeviceProtectedStorage(sa.getBoolean(
+                    R.styleable.AndroidManifestApplication_defaultToDeviceProtectedStorage,
+                    false));
+
+            parsingPackage.setDirectBootAware(sa.getBoolean(
+                    R.styleable.AndroidManifestApplication_directBootAware, false));
+
+            if (sa.hasValueOrEmpty(R.styleable.AndroidManifestApplication_resizeableActivity)) {
+                parsingPackage.setActivitiesResizeModeResizeable(sa.getBoolean(
+                        R.styleable.AndroidManifestApplication_resizeableActivity, true));
+            } else {
+                parsingPackage.setActivitiesResizeModeResizeableViaSdkVersion(
+                        parsingPackage.getTargetSdkVersion() >= Build.VERSION_CODES.N);
+            }
+
+            parsingPackage.setAllowClearUserDataOnFailedRestore(sa.getBoolean(
+                    R.styleable.AndroidManifestApplication_allowClearUserDataOnFailedRestore,
+                    true));
+
+
+            parsingPackage.setAllowAudioPlaybackCapture(sa.getBoolean(
+                    R.styleable.AndroidManifestApplication_allowAudioPlaybackCapture,
+                    parsingPackage.getTargetSdkVersion() >= Build.VERSION_CODES.Q));
+
+            parsingPackage.setRequestLegacyExternalStorage(sa.getBoolean(
+                    R.styleable.AndroidManifestApplication_requestLegacyExternalStorage,
+                    parsingPackage.getTargetSdkVersion() < Build.VERSION_CODES.Q));
+
+            parsingPackage
+                    .setMaxAspectRatio(
+                            sa.getFloat(R.styleable.AndroidManifestApplication_maxAspectRatio, 0))
+                    .setMinAspectRatio(
+                            sa.getFloat(R.styleable.AndroidManifestApplication_minAspectRatio, 0))
+                    .setNetworkSecurityConfigRes(sa.getResourceId(
+                            R.styleable.AndroidManifestApplication_networkSecurityConfig, 0))
+                    .setCategory(sa.getInt(R.styleable.AndroidManifestApplication_appCategory,
+                            ApplicationInfo.CATEGORY_UNDEFINED));
+
+            String str;
+            str = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestApplication_permission, 0);
+            parsingPackage.setPermission((str != null && str.length() > 0) ? str.intern() : null);
+
+            if (parsingPackage.getTargetSdkVersion() >= Build.VERSION_CODES.FROYO) {
+                str = sa.getNonConfigurationString(
+                        R.styleable.AndroidManifestApplication_taskAffinity,
+                        Configuration.NATIVE_CONFIG_VERSION);
+            } else {
+                // Some older apps have been seen to use a resource reference
+                // here that on older builds was ignored (with a warning).  We
+                // need to continue to do this for them so they don't break.
+                str = sa.getNonResourceString(
+                        R.styleable.AndroidManifestApplication_taskAffinity);
+            }
+            String packageName = parsingPackage.getPackageName();
+            String taskAffinity = PackageParser.buildTaskAffinityName(packageName,
+                    packageName,
+                    str, outError);
+
+            if (outError[0] != null) {
+                return parseInput.error(
+                        PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                        outError[0]
+                );
+            }
+
+            parsingPackage.setTaskAffinity(taskAffinity);
+            String factory = sa.getNonResourceString(
+                    R.styleable.AndroidManifestApplication_appComponentFactory);
+            if (factory != null) {
+                String appComponentFactory = buildClassName(packageName, factory);
+                if (appComponentFactory == null) {
+                    return parseInput.error(
+                            PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                            "Empty class name in package " + pkgName
+                    );
+                }
+
+                parsingPackage.setAppComponentFactory(appComponentFactory);
+            }
+
+            parsingPackage.setUsesNonSdkApi(sa.getBoolean(
+                    R.styleable.AndroidManifestApplication_usesNonSdkApi, false));
+
+            parsingPackage.setHasFragileUserData(sa.getBoolean(
+                    R.styleable.AndroidManifestApplication_hasFragileUserData, false));
+
+            CharSequence pname;
+            if (parsingPackage.getTargetSdkVersion() >= Build.VERSION_CODES.FROYO) {
+                pname = sa.getNonConfigurationString(
+                        R.styleable.AndroidManifestApplication_process,
+                        Configuration.NATIVE_CONFIG_VERSION);
+            } else {
+                // Some older apps have been seen to use a resource reference
+                // here that on older builds was ignored (with a warning).  We
+                // need to continue to do this for them so they don't break.
+                pname = sa.getNonResourceString(
+                        R.styleable.AndroidManifestApplication_process);
+            }
+            String processName = PackageParser.buildProcessName(packageName, null, pname, flags,
+                    separateProcesses, outError);
+
+            if (outError[0] != null) {
+                return parseInput.error(
+                        PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                        outError[0]
+                );
+            }
+
+            parsingPackage
+                    .setProcessName(processName)
+                    .setEnabled(
+                            sa.getBoolean(R.styleable.AndroidManifestApplication_enabled,
+                                    true));
+
+            parsingPackage.setIsGame(sa.getBoolean(
+                    R.styleable.AndroidManifestApplication_isGame, false));
+
+            boolean cantSaveState = sa.getBoolean(
+                    R.styleable.AndroidManifestApplication_cantSaveState, false);
+            parsingPackage.setCantSaveState(cantSaveState);
+            if (cantSaveState) {
+                // A heavy-weight application can not be in a custom process.
+                // We can do direct compare because we intern all strings.
+                if (processName != null && !processName.equals(packageName)) {
+                    return parseInput.error(
+                            PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                            "cantSaveState applications can not use custom processes"
+                    );
+                }
+            }
+
+            String classLoaderName = sa.getString(
+                    R.styleable.AndroidManifestApplication_classLoader);
+            parsingPackage
+                    .setUiOptions(sa.getInt(R.styleable.AndroidManifestApplication_uiOptions, 0))
+                    .setClassLoaderName(classLoaderName)
+                    .setZygotePreloadName(
+                            sa.getString(R.styleable.AndroidManifestApplication_zygotePreloadName));
+
+            if (classLoaderName != null
+                    && !ClassLoaderFactory.isValidClassLoaderName(classLoaderName)) {
+                return parseInput.error(
+                        PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                        "Invalid class loader name: " + classLoaderName
+                );
+            }
+        } finally {
+            if (sa != null) {
+                sa.recycle();
+            }
+        }
+
+        final int innerDepth = parser.getDepth();
+        int type;
+        boolean hasActivityOrder = false;
+        boolean hasReceiverOrder = false;
+        boolean hasServiceOrder = false;
+
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
+            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                continue;
+            }
+
+            String tagName = parser.getName();
+            switch (tagName) {
+                case "activity":
+                    ComponentParseUtils.ParsedActivity activity =
+                            ComponentParseUtils.parseActivity(separateProcesses,
+                                    parsingPackage,
+                                    res, parser, flags,
+                                    outError, false,
+                                    parsingPackage.isBaseHardwareAccelerated());
+                    if (activity == null) {
+                        return parseInput.error(
+                                PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                                outError[0]
+                        );
+                    }
+
+                    hasActivityOrder |= (activity.order != 0);
+                    parsingPackage.addActivity(activity);
+                    break;
+                case "receiver":
+                    activity = ComponentParseUtils.parseActivity(separateProcesses,
+                            parsingPackage,
+                            res, parser,
+                            flags, outError,
+                            true, false);
+                    if (activity == null) {
+                        return parseInput.error(
+                                PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                                outError[0]
+                        );
+                    }
+
+                    hasReceiverOrder |= (activity.order != 0);
+                    parsingPackage.addReceiver(activity);
+                    break;
+                case "service":
+                    ComponentParseUtils.ParsedService s = ComponentParseUtils.parseService(
+                            separateProcesses,
+                            parsingPackage,
+                            res, parser, flags,
+                            outError);
+                    if (s == null) {
+                        return parseInput.error(
+                                PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                                outError[0]
+                        );
+                    }
+
+                    hasServiceOrder |= (s.order != 0);
+                    parsingPackage.addService(s);
+                    break;
+                case "provider":
+                    ComponentParseUtils.ParsedProvider p = ComponentParseUtils.parseProvider(
+                            separateProcesses,
+                            parsingPackage,
+                            res, parser, flags,
+                            outError
+                    );
+                    if (p == null) {
+                        return parseInput.error(
+                                PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                                outError[0]
+                        );
+                    }
+
+                    parsingPackage.addProvider(p);
+                    break;
+                case "activity-alias":
+                    activity = ComponentParseUtils.parseActivityAlias(
+                            parsingPackage,
+                            res,
+                            parser,
+                            outError
+                    );
+                    if (activity == null) {
+                        return parseInput.error(
+                                PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                                outError[0]
+                        );
+                    }
+
+                    hasActivityOrder |= (activity.order != 0);
+                    parsingPackage.addActivity(activity);
+                    break;
+                case "meta-data":
+                    // note: application meta-data is stored off to the side, so it can
+                    // remain null in the primary copy (we like to avoid extra copies because
+                    // it can be large)
+                    Bundle appMetaData = parseMetaData(parsingPackage, res, parser,
+                            parsingPackage.getAppMetaData(),
+                            outError);
+                    if (appMetaData == null) {
+                        return parseInput.error(
+                                PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                                outError[0]
+                        );
+                    }
+
+                    parsingPackage.setAppMetaData(appMetaData);
+                    break;
+                case "static-library":
+                    sa = res.obtainAttributes(parser,
+                            R.styleable.AndroidManifestStaticLibrary);
+
+                    // Note: don't allow this value to be a reference to a resource
+                    // that may change.
+                    String lname = sa.getNonResourceString(
+                            R.styleable.AndroidManifestStaticLibrary_name);
+                    final int version = sa.getInt(
+                            R.styleable.AndroidManifestStaticLibrary_version, -1);
+                    final int versionMajor = sa.getInt(
+                            R.styleable.AndroidManifestStaticLibrary_versionMajor,
+                            0);
+
+                    sa.recycle();
+
+                    // Since the app canot run without a static lib - fail if malformed
+                    if (lname == null || version < 0) {
+                        return parseInput.error(
+                                PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                                "Bad static-library declaration name: " + lname
+                                        + " version: " + version
+                        );
+                    }
+
+                    if (parsingPackage.getSharedUserId() != null) {
+                        return parseInput.error(
+                                PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID,
+                                "sharedUserId not allowed in static shared library"
+                        );
+                    }
+
+                    if (parsingPackage.getStaticSharedLibName() != null) {
+                        return parseInput.error(
+                                PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                                "Multiple static-shared libs for package " + pkgName
+                        );
+                    }
+
+                    parsingPackage.setStaticSharedLibName(lname.intern());
+                    if (version >= 0) {
+                        parsingPackage.setStaticSharedLibVersion(
+                                PackageInfo.composeLongVersionCode(versionMajor, version));
+                    } else {
+                        parsingPackage.setStaticSharedLibVersion(version);
+                    }
+                    parsingPackage.setStaticSharedLibrary(true);
+
+                    XmlUtils.skipCurrentTag(parser);
+
+                    break;
+                case "library":
+                    sa = res.obtainAttributes(parser,
+                            R.styleable.AndroidManifestLibrary);
+
+                    // Note: don't allow this value to be a reference to a resource
+                    // that may change.
+                    lname = sa.getNonResourceString(
+                            R.styleable.AndroidManifestLibrary_name);
+
+                    sa.recycle();
+
+                    if (lname != null) {
+                        lname = lname.intern();
+                        if (!ArrayUtils.contains(parsingPackage.getLibraryNames(), lname)) {
+                            parsingPackage.addLibraryName(lname);
+                        }
+                    }
+
+                    XmlUtils.skipCurrentTag(parser);
+
+                    break;
+                case "uses-static-library":
+                    ParseResult parseResult = parseUsesStaticLibrary(parseInput, parsingPackage,
+                            res, parser);
+                    if (!parseResult.isSuccess()) {
+                        return parseResult;
+                    }
+                    break;
+                case "uses-library":
+                    sa = res.obtainAttributes(parser,
+                            R.styleable.AndroidManifestUsesLibrary);
+
+                    // Note: don't allow this value to be a reference to a resource
+                    // that may change.
+                    lname = sa.getNonResourceString(
+                            R.styleable.AndroidManifestUsesLibrary_name);
+                    boolean req = sa.getBoolean(
+                            R.styleable.AndroidManifestUsesLibrary_required,
+                            true);
+
+                    sa.recycle();
+
+                    if (lname != null) {
+                        lname = lname.intern();
+                        if (req) {
+                            parsingPackage.addUsesLibrary(lname);
+                        } else {
+                            parsingPackage.addUsesOptionalLibrary(lname);
+                        }
+                    }
+
+                    XmlUtils.skipCurrentTag(parser);
+
+                    break;
+                case "uses-package":
+                    // Dependencies for app installers; we don't currently try to
+                    // enforce this.
+                    XmlUtils.skipCurrentTag(parser);
+                    break;
+                case "profileable":
+                    sa = res.obtainAttributes(parser,
+                            R.styleable.AndroidManifestProfileable);
+                    if (sa.getBoolean(
+                            R.styleable.AndroidManifestProfileable_shell, false)) {
+                        parsingPackage.setProfileableByShell(true);
+                    }
+                    XmlUtils.skipCurrentTag(parser);
+
+                default:
+                    if (!PackageParser.RIGID_PARSER) {
+                        Slog.w(TAG, "Unknown element under <application>: " + tagName
+                                + " at " + parsingPackage.getBaseCodePath() + " "
+                                + parser.getPositionDescription());
+                        XmlUtils.skipCurrentTag(parser);
+                        continue;
+                    } else {
+                        return parseInput.error(
+                                PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                                "Bad element under <application>: " + tagName
+                        );
+                    }
+            }
+        }
+
+        if (TextUtils.isEmpty(parsingPackage.getStaticSharedLibName())) {
+            // Add a hidden app detail activity to normal apps which forwards user to App Details
+            // page.
+            ComponentParseUtils.ParsedActivity a = generateAppDetailsHiddenActivity(
+                    parsingPackage,
+                    outError
+            );
+            // Ignore errors here
+            parsingPackage.addActivity(a);
+        }
+
+        if (hasActivityOrder) {
+            parsingPackage.sortActivities();
+        }
+        if (hasReceiverOrder) {
+            parsingPackage.sortReceivers();
+        }
+        if (hasServiceOrder) {
+            parsingPackage.sortServices();
+        }
+        // Must be ran after the entire {@link ApplicationInfo} has been fully processed and after
+        // every activity info has had a chance to set it from its attributes.
+        setMaxAspectRatio(parsingPackage);
+        setMinAspectRatio(parsingPackage, callback);
+
+        parsingPackage.setHasDomainUrls(hasDomainURLs(parsingPackage));
+
+        return parseInput.success(parsingPackage);
+    }
+
+    private static ParseResult parseUsesStaticLibrary(
+            ParseInput parseInput,
+            ParsingPackage parsingPackage,
+            Resources res,
+            XmlResourceParser parser
+    ) throws XmlPullParserException, IOException {
+        TypedArray sa = res.obtainAttributes(parser,
+                R.styleable.AndroidManifestUsesStaticLibrary);
+
+        // Note: don't allow this value to be a reference to a resource that may change.
+        String lname = sa.getNonResourceString(
+                R.styleable.AndroidManifestUsesLibrary_name);
+        final int version = sa.getInt(
+                R.styleable.AndroidManifestUsesStaticLibrary_version, -1);
+        String certSha256Digest = sa.getNonResourceString(com.android.internal.R.styleable
+                .AndroidManifestUsesStaticLibrary_certDigest);
+        sa.recycle();
+
+        // Since an APK providing a static shared lib can only provide the lib - fail if malformed
+        if (lname == null || version < 0 || certSha256Digest == null) {
+            return parseInput.error(
+                    PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                    "Bad uses-static-library declaration name: " + lname + " version: "
+                            + version + " certDigest" + certSha256Digest
+            );
+        }
+
+        // Can depend only on one version of the same library
+        List<String> usesStaticLibraries = parsingPackage.getUsesStaticLibraries();
+        if (usesStaticLibraries != null && usesStaticLibraries.contains(lname)) {
+            return parseInput.error(
+                    PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                    "Depending on multiple versions of static library " + lname
+            );
+        }
+
+        lname = lname.intern();
+        // We allow ":" delimiters in the SHA declaration as this is the format
+        // emitted by the certtool making it easy for developers to copy/paste.
+        certSha256Digest = certSha256Digest.replace(":", "").toLowerCase();
+
+        // Fot apps targeting O-MR1 we require explicit enumeration of all certs.
+        String[] additionalCertSha256Digests = EmptyArray.STRING;
+        if (parsingPackage.getTargetSdkVersion() >= Build.VERSION_CODES.O_MR1) {
+            // TODO(b/135203078): Remove, replace with ParseResult
+            String[] outError = new String[1];
+            additionalCertSha256Digests = parseAdditionalCertificates(res, parser, outError);
+            if (additionalCertSha256Digests == null || outError[0] != null) {
+                return parseInput.error(
+                        PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                        outError[0]
+                );
+            }
+        } else {
+            XmlUtils.skipCurrentTag(parser);
+        }
+
+        final String[] certSha256Digests = new String[additionalCertSha256Digests.length + 1];
+        certSha256Digests[0] = certSha256Digest;
+        System.arraycopy(additionalCertSha256Digests, 0, certSha256Digests,
+                1, additionalCertSha256Digests.length);
+
+        parsingPackage.addUsesStaticLibrary(lname)
+                .addUsesStaticLibraryVersion(version)
+                .addUsesStaticLibraryCertDigests(certSha256Digests);
+
+        return parseInput.success(parsingPackage);
+    }
+
+    private static String[] parseAdditionalCertificates(
+            Resources resources,
+            XmlResourceParser parser,
+            String[] outError
+    ) throws XmlPullParserException, IOException {
+        String[] certSha256Digests = EmptyArray.STRING;
+
+        int outerDepth = parser.getDepth();
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                continue;
+            }
+
+            final String nodeName = parser.getName();
+            if (nodeName.equals("additional-certificate")) {
+                final TypedArray sa = resources.obtainAttributes(parser, com.android.internal.
+                        R.styleable.AndroidManifestAdditionalCertificate);
+                String certSha256Digest = sa.getNonResourceString(com.android.internal.
+                        R.styleable.AndroidManifestAdditionalCertificate_certDigest);
+                sa.recycle();
+
+                if (TextUtils.isEmpty(certSha256Digest)) {
+                    outError[0] = "Bad additional-certificate declaration with empty"
+                            + " certDigest:" + certSha256Digest;
+                    XmlUtils.skipCurrentTag(parser);
+                    sa.recycle();
+                    return null;
+                }
+
+                // We allow ":" delimiters in the SHA declaration as this is the format
+                // emitted by the certtool making it easy for developers to copy/paste.
+                certSha256Digest = certSha256Digest.replace(":", "").toLowerCase();
+                certSha256Digests = ArrayUtils.appendElement(String.class,
+                        certSha256Digests, certSha256Digest);
+            } else {
+                XmlUtils.skipCurrentTag(parser);
+            }
+        }
+
+        return certSha256Digests;
+    }
+
+    /**
+     * Generate activity object that forwards user to App Details page automatically.
+     * This activity should be invisible to user and user should not know or see it.
+     *
+     * @hide
+     */
+    @NonNull
+    private static ComponentParseUtils.ParsedActivity generateAppDetailsHiddenActivity(
+            ParsingPackage parsingPackage,
+            String[] outError
+    ) {
+        String packageName = parsingPackage.getPackageName();
+        String processName = parsingPackage.getProcessName();
+        boolean hardwareAccelerated = parsingPackage.isBaseHardwareAccelerated();
+        int uiOptions = parsingPackage.getUiOptions();
+
+        // Build custom App Details activity info instead of parsing it from xml
+        ComponentParseUtils.ParsedActivity activity = new ComponentParseUtils.ParsedActivity();
+        activity.setPackageName(packageName);
+
+        activity.theme = android.R.style.Theme_NoDisplay;
+        activity.exported = true;
+        activity.className = PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME;
+        activity.setProcessName(processName, processName);
+        activity.uiOptions = uiOptions;
+        activity.taskAffinity = PackageParser.buildTaskAffinityName(packageName,
+                packageName,
+                ":app_details", outError);
+        activity.enabled = true;
+        activity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
+        activity.documentLaunchMode = ActivityInfo.DOCUMENT_LAUNCH_NONE;
+        activity.maxRecents = ActivityTaskManager.getDefaultAppRecentsLimitStatic();
+        activity.configChanges = PackageParser.getActivityConfigChanges(0, 0);
+        activity.softInputMode = 0;
+        activity.persistableMode = ActivityInfo.PERSIST_NEVER;
+        activity.screenOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
+        activity.resizeMode = RESIZE_MODE_FORCE_RESIZEABLE;
+        activity.lockTaskLaunchMode = 0;
+        activity.directBootAware = false;
+        activity.rotationAnimation = ROTATION_ANIMATION_UNSPECIFIED;
+        activity.colorMode = ActivityInfo.COLOR_MODE_DEFAULT;
+        if (hardwareAccelerated) {
+            activity.flags |= ActivityInfo.FLAG_HARDWARE_ACCELERATED;
+        }
+
+        return activity;
+    }
+
+    /**
+     * Check if one of the IntentFilter as both actions DEFAULT / VIEW and a HTTP/HTTPS data URI
+     */
+    private static boolean hasDomainURLs(
+            ParsingPackage parsingPackage) {
+        final List<ComponentParseUtils.ParsedActivity> activities = parsingPackage.getActivities();
+        final int countActivities = activities.size();
+        for (int n = 0; n < countActivities; n++) {
+            ComponentParseUtils.ParsedActivity activity = activities.get(n);
+            List<ComponentParseUtils.ParsedActivityIntentInfo> filters = activity.intents;
+            if (filters == null) continue;
+            final int countFilters = filters.size();
+            for (int m = 0; m < countFilters; m++) {
+                ComponentParseUtils.ParsedActivityIntentInfo aii = filters.get(m);
+                if (!aii.hasAction(Intent.ACTION_VIEW)) continue;
+                if (!aii.hasAction(Intent.ACTION_DEFAULT)) continue;
+                if (aii.hasDataScheme(IntentFilter.SCHEME_HTTP) ||
+                        aii.hasDataScheme(IntentFilter.SCHEME_HTTPS)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Sets the max aspect ratio of every child activity that doesn't already have an aspect
+     * ratio set.
+     */
+    private static void setMaxAspectRatio(
+            ParsingPackage parsingPackage) {
+        // 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 = parsingPackage.getTargetSdkVersion() < O
+                ? PackageParser.DEFAULT_PRE_O_MAX_ASPECT_RATIO : 0;
+
+        float packageMaxAspectRatio = parsingPackage.getMaxAspectRatio();
+        if (packageMaxAspectRatio != 0) {
+            // Use the application max aspect ration as default if set.
+            maxAspectRatio = packageMaxAspectRatio;
+        } else {
+            Bundle appMetaData = parsingPackage.getAppMetaData();
+            if (appMetaData != null && appMetaData.containsKey(
+                    PackageParser.METADATA_MAX_ASPECT_RATIO)) {
+                maxAspectRatio = appMetaData.getFloat(PackageParser.METADATA_MAX_ASPECT_RATIO,
+                        maxAspectRatio);
+            }
+        }
+
+        if (parsingPackage.getActivities() != null) {
+            for (ComponentParseUtils.ParsedActivity activity : parsingPackage.getActivities()) {
+                // If the max aspect ratio for the activity has already been set, skip.
+                if (activity.hasMaxAspectRatio()) {
+                    continue;
+                }
+
+                // By default we prefer to use a values defined on the activity directly than values
+                // defined on the application. We do not check the styled attributes on the activity
+                // as it would have already been set when we processed the activity. We wait to
+                // 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.metaData != null
+                        ? activity.metaData.getFloat(PackageParser.METADATA_MAX_ASPECT_RATIO,
+                        maxAspectRatio)
+                        : maxAspectRatio;
+
+                activity.setMaxAspectRatio(activity.resizeMode, activityAspectRatio);
+            }
+        }
+    }
+
+    /**
+     * Sets the min aspect ratio of every child activity that doesn't already have an aspect
+     * ratio set.
+     */
+    private static void setMinAspectRatio(
+            ParsingPackage parsingPackage,
+            PackageParser.Callback callback
+    ) {
+        final float minAspectRatio;
+        float packageMinAspectRatio = parsingPackage.getMinAspectRatio();
+        if (packageMinAspectRatio != 0) {
+            // Use the application max aspect ration as default if set.
+            minAspectRatio = packageMinAspectRatio;
+        } else {
+            // Default to (1.33) 4:3 aspect ratio for pre-Q apps and unset for Q and greater.
+            // NOTE: 4:3 was the min aspect ratio Android devices can support pre-Q per the CDD,
+            // except for watches which always supported 1:1.
+            minAspectRatio = parsingPackage.getTargetSdkVersion() >= Build.VERSION_CODES.Q
+                    ? 0
+                    : (callback != null && callback.hasFeature(FEATURE_WATCH))
+                            ? PackageParser.DEFAULT_PRE_Q_MIN_ASPECT_RATIO_WATCH
+                            : PackageParser.DEFAULT_PRE_Q_MIN_ASPECT_RATIO;
+        }
+
+        if (parsingPackage.getActivities() != null) {
+            for (ComponentParseUtils.ParsedActivity activity : parsingPackage.getActivities()) {
+                if (activity.hasMinAspectRatio()) {
+                    continue;
+                }
+                activity.setMinAspectRatio(activity.resizeMode, minAspectRatio);
+            }
+        }
+    }
+
+    private static ParseResult parseOverlay(
+            ParseInput parseInput,
+            ParsingPackage parsingPackage,
+            Resources res,
+            XmlResourceParser parser
+    ) throws IOException, XmlPullParserException {
+
+        TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestResourceOverlay);
+        String target = sa.getString(
+                R.styleable.AndroidManifestResourceOverlay_targetPackage);
+        String targetName = sa.getString(
+                R.styleable.AndroidManifestResourceOverlay_targetName);
+        String category = sa.getString(
+                R.styleable.AndroidManifestResourceOverlay_category);
+        int priority = sa.getInt(R.styleable.AndroidManifestResourceOverlay_priority,
+                0);
+        boolean isStatic = sa.getBoolean(
+                R.styleable.AndroidManifestResourceOverlay_isStatic, false);
+
+        if (target == null) {
+            return parseInput.error(
+                    PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                    "<overlay> does not specify a target package"
+            );
+        }
+
+        if (priority < 0 || priority > 9999) {
+            return parseInput.error(
+                    PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                    "<overlay> priority must be between 0 and 9999"
+            );
+        }
+
+        // check to see if overlay should be excluded based on system property condition
+        String propName = sa.getString(
+                R.styleable.AndroidManifestResourceOverlay_requiredSystemPropertyName);
+        String propValue = sa.getString(
+                R.styleable.AndroidManifestResourceOverlay_requiredSystemPropertyValue);
+        if (!checkOverlayRequiredSystemProperty(propName, propValue)) {
+            Slog.i(TAG, "Skipping target and overlay pair " + target + " and "
+                    + parsingPackage.getBaseCodePath()
+                    + ": overlay ignored due to required system property: "
+                    + propName + " with value: " + propValue);
+            return parseInput.error(
+                    PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                    "Skipping target and overlay pair " + target + " and "
+                            + parsingPackage.getBaseCodePath()
+                            + ": overlay ignored due to required system property: "
+                            + propName + " with value: " + propValue
+            );
+        }
+
+        parsingPackage
+                .setIsOverlay(true)
+                .setOverlayTarget(target)
+                .setOverlayTargetName(targetName)
+                .setOverlayCategory(category)
+                .setOverlayPriority(priority)
+                .setOverlayIsStatic(isStatic);
+
+        sa.recycle();
+
+        XmlUtils.skipCurrentTag(parser);
+        return parseInput.success(parsingPackage);
+    }
+
+    private static boolean parseProtectedBroadcast(
+            ParsingPackage parsingPackage,
+            Resources res,
+            XmlResourceParser parser
+    ) throws IOException, XmlPullParserException {
+        TypedArray sa = res.obtainAttributes(parser,
+                R.styleable.AndroidManifestProtectedBroadcast);
+
+        // Note: don't allow this value to be a reference to a resource
+        // that may change.
+        String name = sa.getNonResourceString(R.styleable.AndroidManifestProtectedBroadcast_name);
+
+        sa.recycle();
+
+        if (name != null) {
+            parsingPackage.addProtectedBroadcast(name);
+        }
+
+        XmlUtils.skipCurrentTag(parser);
+        return true;
+    }
+
+    private static boolean parseSupportScreens(
+            ParsingPackage parsingPackage,
+            Resources res,
+            XmlResourceParser parser
+    ) throws IOException, XmlPullParserException {
+        TypedArray sa = res.obtainAttributes(parser,
+                R.styleable.AndroidManifestSupportsScreens);
+
+        int requiresSmallestWidthDp = sa.getInteger(
+                R.styleable.AndroidManifestSupportsScreens_requiresSmallestWidthDp,
+                0);
+        int compatibleWidthLimitDp = sa.getInteger(
+                R.styleable.AndroidManifestSupportsScreens_compatibleWidthLimitDp,
+                0);
+        int largestWidthLimitDp = sa.getInteger(
+                R.styleable.AndroidManifestSupportsScreens_largestWidthLimitDp,
+                0);
+
+        // This is a trick to get a boolean and still able to detect
+        // if a value was actually set.
+        parsingPackage
+                .setSupportsSmallScreens(
+                        sa.getInteger(R.styleable.AndroidManifestSupportsScreens_smallScreens, 1))
+                .setSupportsNormalScreens(
+                        sa.getInteger(R.styleable.AndroidManifestSupportsScreens_normalScreens, 1))
+                .setSupportsLargeScreens(
+                        sa.getInteger(R.styleable.AndroidManifestSupportsScreens_largeScreens, 1))
+                .setSupportsXLargeScreens(
+                        sa.getInteger(R.styleable.AndroidManifestSupportsScreens_xlargeScreens, 1))
+                .setResizeable(
+                        sa.getInteger(R.styleable.AndroidManifestSupportsScreens_resizeable, 1))
+                .setAnyDensity(
+                        sa.getInteger(R.styleable.AndroidManifestSupportsScreens_anyDensity, 1))
+                .setRequiresSmallestWidthDp(requiresSmallestWidthDp)
+                .setCompatibleWidthLimitDp(compatibleWidthLimitDp)
+                .setLargestWidthLimitDp(largestWidthLimitDp);
+
+        sa.recycle();
+
+        XmlUtils.skipCurrentTag(parser);
+        return true;
+    }
+
+    private static ParseResult parseInstrumentation(
+            ParseInput parseInput,
+            ParsingPackage parsingPackage,
+            Resources res,
+            XmlResourceParser parser
+    ) throws XmlPullParserException, IOException {
+        // TODO(b/135203078): Remove, replace with ParseResult
+        String[] outError = new String[1];
+
+        ComponentParseUtils.ParsedInstrumentation parsedInstrumentation =
+                ComponentParseUtils.parseInstrumentation(parsingPackage,
+                        res, parser, outError);
+
+        if (parsedInstrumentation == null || outError[0] != null) {
+            return parseInput.error(
+                    PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                    outError[0]
+            );
+        }
+
+        parsingPackage.addInstrumentation(parsedInstrumentation);
+
+        return parseInput.success(parsingPackage);
+    }
+
+    private static boolean parseOriginalPackage(
+            ParsingPackage parsingPackage,
+            Resources res,
+            XmlResourceParser parser
+    ) throws IOException, XmlPullParserException {
+        TypedArray sa = res.obtainAttributes(parser,
+                R.styleable.AndroidManifestOriginalPackage);
+
+        String orig = sa.getNonConfigurationString(
+                R.styleable.AndroidManifestOriginalPackage_name,
+                0);
+        if (!parsingPackage.getPackageName().equals(orig)) {
+            if (parsingPackage.getOriginalPackages() == null) {
+                parsingPackage.setRealPackage(parsingPackage.getPackageName());
+            }
+            parsingPackage.addOriginalPackage(orig);
+        }
+
+        sa.recycle();
+
+        XmlUtils.skipCurrentTag(parser);
+        return true;
+    }
+
+    private static boolean parseAdoptPermissions(
+            ParsingPackage parsingPackage,
+            Resources res,
+            XmlResourceParser parser
+    ) throws IOException, XmlPullParserException {
+        TypedArray sa = res.obtainAttributes(parser,
+                R.styleable.AndroidManifestOriginalPackage);
+
+        String name = sa.getNonConfigurationString(
+                R.styleable.AndroidManifestOriginalPackage_name,
+                0);
+
+        sa.recycle();
+
+        if (name != null) {
+            parsingPackage.addAdoptPermission(name);
+        }
+
+        XmlUtils.skipCurrentTag(parser);
+        return true;
+    }
+
+    private static void convertNewPermissions(
+            ParsingPackage packageToParse) {
+        final int NP = PackageParser.NEW_PERMISSIONS.length;
+        StringBuilder newPermsMsg = null;
+        for (int ip = 0; ip < NP; ip++) {
+            final PackageParser.NewPermissionInfo npi
+                    = PackageParser.NEW_PERMISSIONS[ip];
+            if (packageToParse.getTargetSdkVersion() >= npi.sdkVersion) {
+                break;
+            }
+            if (!packageToParse.getRequestedPermissions().contains(npi.name)) {
+                if (newPermsMsg == null) {
+                    newPermsMsg = new StringBuilder(128);
+                    newPermsMsg.append(packageToParse.getPackageName());
+                    newPermsMsg.append(": compat added ");
+                } else {
+                    newPermsMsg.append(' ');
+                }
+                newPermsMsg.append(npi.name);
+                packageToParse.addRequestedPermission(npi.name);
+                packageToParse.addImplicitPermission(npi.name);
+            }
+        }
+        if (newPermsMsg != null) {
+            Slog.i(TAG, newPermsMsg.toString());
+        }
+    }
+
+    private static void convertSplitPermissions(ParsingPackage packageToParse) {
+        List<SplitPermissionInfoParcelable> splitPermissions;
+
+        try {
+            splitPermissions = ActivityThread.getPermissionManager().getSplitPermissions();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+
+        final int listSize = splitPermissions.size();
+        for (int is = 0; is < listSize; is++) {
+            final SplitPermissionInfoParcelable spi = splitPermissions.get(is);
+            List<String> requestedPermissions = packageToParse.getRequestedPermissions();
+            if (packageToParse.getTargetSdkVersion() >= spi.getTargetSdk()
+                    || !requestedPermissions.contains(spi.getSplitPermission())) {
+                continue;
+            }
+            final List<String> newPerms = spi.getNewPermissions();
+            for (int in = 0; in < newPerms.size(); in++) {
+                final String perm = newPerms.get(in);
+                if (!requestedPermissions.contains(perm)) {
+                    packageToParse.addRequestedPermission(perm);
+                    packageToParse.addImplicitPermission(perm);
+                }
+            }
+        }
+    }
+
+    private static boolean checkOverlayRequiredSystemProperty(String propName, String propValue) {
+        if (TextUtils.isEmpty(propName) || TextUtils.isEmpty(propValue)) {
+            if (!TextUtils.isEmpty(propName) || !TextUtils.isEmpty(propValue)) {
+                // malformed condition - incomplete
+                Slog.w(TAG, "Disabling overlay - incomplete property :'" + propName
+                        + "=" + propValue + "' - require both requiredSystemPropertyName"
+                        + " AND requiredSystemPropertyValue to be specified.");
+                return false;
+            }
+            // no valid condition set - so no exclusion criteria, overlay will be included.
+            return true;
+        }
+
+        // check property value - make sure it is both set and equal to expected value
+        final String currValue = SystemProperties.get(propName);
+        return (currValue != null && currValue.equals(propValue));
+    }
+
+    /**
+     * This is a pre-density application which will get scaled - instead of being pixel perfect.
+     * This type of application is not resizable.
+     *
+     * @param parsingPackage The package which needs to be marked as unresizable.
+     */
+    private static void adjustPackageToBeUnresizeableAndUnpipable(
+            ParsingPackage parsingPackage) {
+        if (parsingPackage.getActivities() != null) {
+            for (ComponentParseUtils.ParsedActivity a : parsingPackage.getActivities()) {
+                a.resizeMode = RESIZE_MODE_UNRESIZEABLE;
+                a.flags &= ~FLAG_SUPPORTS_PICTURE_IN_PICTURE;
+            }
+        }
+    }
+
+    private static String validateName(String name, boolean requireSeparator,
+            boolean requireFilename) {
+        final int N = name.length();
+        boolean hasSep = false;
+        boolean front = true;
+        for (int i = 0; i < N; i++) {
+            final char c = name.charAt(i);
+            if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
+                front = false;
+                continue;
+            }
+            if (!front) {
+                if ((c >= '0' && c <= '9') || c == '_') {
+                    continue;
+                }
+            }
+            if (c == '.') {
+                hasSep = true;
+                front = true;
+                continue;
+            }
+            return "bad character '" + c + "'";
+        }
+        if (requireFilename && !FileUtils.isValidExtFilename(name)) {
+            return "Invalid filename";
+        }
+        return hasSep || !requireSeparator
+                ? null : "must have at least one '.' separator";
+    }
+
+    public static Bundle parseMetaData(
+            ParsingPackage parsingPackage,
+            Resources res,
+            XmlResourceParser parser, Bundle data, String[] outError)
+            throws XmlPullParserException, IOException {
+
+        TypedArray sa = res.obtainAttributes(parser,
+                R.styleable.AndroidManifestMetaData);
+
+        if (data == null) {
+            data = new Bundle();
+        }
+
+        String name = sa.getNonConfigurationString(
+                R.styleable.AndroidManifestMetaData_name, 0);
+        if (name == null) {
+            outError[0] = "<meta-data> requires an android:name attribute";
+            sa.recycle();
+            return null;
+        }
+
+        name = name.intern();
+
+        TypedValue v = sa.peekValue(
+                R.styleable.AndroidManifestMetaData_resource);
+        if (v != null && v.resourceId != 0) {
+            //Slog.i(TAG, "Meta data ref " + name + ": " + v);
+            data.putInt(name, v.resourceId);
+        } else {
+            v = sa.peekValue(
+                    R.styleable.AndroidManifestMetaData_value);
+            //Slog.i(TAG, "Meta data " + name + ": " + v);
+            if (v != null) {
+                if (v.type == TypedValue.TYPE_STRING) {
+                    CharSequence cs = v.coerceToString();
+                    data.putString(name, cs != null ? cs.toString() : null);
+                } else if (v.type == TypedValue.TYPE_INT_BOOLEAN) {
+                    data.putBoolean(name, v.data != 0);
+                } else if (v.type >= TypedValue.TYPE_FIRST_INT
+                        && v.type <= TypedValue.TYPE_LAST_INT) {
+                    data.putInt(name, v.data);
+                } else if (v.type == TypedValue.TYPE_FLOAT) {
+                    data.putFloat(name, v.getFloat());
+                } else {
+                    if (!PackageParser.RIGID_PARSER) {
+                        Slog.w(TAG,
+                                "<meta-data> only supports string, integer, float, color, "
+                                        + "boolean, and resource reference types: "
+                                        + parser.getName() + " at "
+                                        + parsingPackage.getBaseCodePath() + " "
+                                        + parser.getPositionDescription());
+                    } else {
+                        outError[0] =
+                                "<meta-data> only supports string, integer, float, color, "
+                                        + "boolean, and resource reference types";
+                        data = null;
+                    }
+                }
+            } else {
+                outError[0] = "<meta-data> requires an android:value or android:resource attribute";
+                data = null;
+            }
+        }
+
+        sa.recycle();
+
+        XmlUtils.skipCurrentTag(parser);
+
+        return data;
+    }
+
+    /**
+     * Collect certificates from all the APKs described in the given package,
+     * populating {@link AndroidPackageWrite#setSigningDetails(SigningDetails)}. Also asserts that
+     * all APK contents are signed correctly and consistently.
+     */
+    public static void collectCertificates(AndroidPackage pkg, boolean skipVerify)
+            throws PackageParserException {
+        pkg.mutate().setSigningDetails(SigningDetails.UNKNOWN);
+
+        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates");
+        try {
+            pkg.mutate().setSigningDetails(collectCertificates(
+                    pkg.getBaseCodePath(),
+                    skipVerify,
+                    pkg.isStaticSharedLibrary(),
+                    pkg.getSigningDetails()
+            ));
+
+            String[] splitCodePaths = pkg.getSplitCodePaths();
+            if (!ArrayUtils.isEmpty(splitCodePaths)) {
+                for (int i = 0; i < splitCodePaths.length; i++) {
+                    pkg.mutate().setSigningDetails(collectCertificates(
+                            splitCodePaths[i],
+                            skipVerify,
+                            pkg.isStaticSharedLibrary(),
+                            pkg.getSigningDetails()
+                    ));
+                }
+            }
+        } finally {
+            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+        }
+    }
+
+    public static SigningDetails collectCertificates(
+            String baseCodePath,
+            boolean skipVerify,
+            boolean isStaticSharedLibrary,
+            @NonNull SigningDetails existingSigningDetails
+    ) throws PackageParserException {
+        int minSignatureScheme = SigningDetails.SignatureSchemeVersion.JAR;
+        if (isStaticSharedLibrary) {
+            // must use v2 signing scheme
+            minSignatureScheme = SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V2;
+        }
+        SigningDetails verified;
+        if (skipVerify) {
+            // systemDir APKs are already trusted, save time by not verifying
+            verified = ApkSignatureVerifier.unsafeGetCertsWithoutVerification(
+                    baseCodePath, minSignatureScheme);
+        } else {
+            verified = ApkSignatureVerifier.verify(baseCodePath, minSignatureScheme);
+        }
+
+        // Verify that entries are signed consistently with the first pkg
+        // we encountered. Note that for splits, certificates may have
+        // already been populated during an earlier parse of a base APK.
+        if (existingSigningDetails == SigningDetails.UNKNOWN) {
+            return verified;
+        } else {
+            if (!Signature.areExactMatch(existingSigningDetails.signatures, verified.signatures)) {
+                throw new PackageParserException(
+                        INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES,
+                        baseCodePath + " has mismatched certificates");
+            }
+
+            return existingSigningDetails;
+        }
+    }
+
+    @Nullable
+    public static String buildClassName(String pkg, CharSequence clsSeq) {
+        if (clsSeq == null || clsSeq.length() <= 0) {
+            return null;
+        }
+        String cls = clsSeq.toString();
+        char c = cls.charAt(0);
+        if (c == '.') {
+            return pkg + cls;
+        }
+        if (cls.indexOf('.') < 0) {
+            StringBuilder b = new StringBuilder(pkg);
+            b.append('.');
+            b.append(cls);
+            return b.toString();
+        }
+        return cls;
+    }
+
+    public interface ParseInput {
+        ParseResult success(ParsingPackage result);
+
+        ParseResult error(int parseError);
+
+        ParseResult error(int parseError, String errorMessage);
+    }
+
+    public static class ParseResult implements ParseInput {
+
+        private static final boolean DEBUG_FILL_STACK_TRACE = false;
+
+        private ParsingPackage result;
+
+        private int parseError;
+        private String errorMessage;
+
+        public ParseInput reset() {
+            this.result = null;
+            this.parseError = PackageManager.INSTALL_SUCCEEDED;
+            this.errorMessage = null;
+            return this;
+        }
+
+        @Override
+        public ParseResult success(ParsingPackage result) {
+            if (parseError != PackageManager.INSTALL_SUCCEEDED || errorMessage != null) {
+                throw new IllegalStateException("Cannot set to success after set to error");
+            }
+            this.result = result;
+            return this;
+        }
+
+        @Override
+        public ParseResult error(int parseError) {
+            return error(parseError, null);
+        }
+
+        @Override
+        public ParseResult error(int parseError, String errorMessage) {
+            this.parseError = parseError;
+            this.errorMessage = errorMessage;
+
+            if (DEBUG_FILL_STACK_TRACE) {
+                this.errorMessage += Arrays.toString(new Exception().getStackTrace());
+            }
+
+            return this;
+        }
+
+        public ParsingPackage getResultAndNull() {
+            ParsingPackage result = this.result;
+            this.result = null;
+            return result;
+        }
+
+        public boolean isSuccess() {
+            return parseError == PackageManager.INSTALL_SUCCEEDED;
+        }
+
+        public int getParseError() {
+            return parseError;
+        }
+
+        public String getErrorMessage() {
+            return errorMessage;
+        }
+    }
+}
diff --git a/core/java/android/content/pm/parsing/ComponentParseUtils.java b/core/java/android/content/pm/parsing/ComponentParseUtils.java
new file mode 100644
index 0000000..adf2a4f
--- /dev/null
+++ b/core/java/android/content/pm/parsing/ComponentParseUtils.java
@@ -0,0 +1,3289 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm.parsing;
+
+import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
+import static android.content.pm.ActivityInfo.FLAG_SUPPORTS_PICTURE_IN_PICTURE;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED;
+
+import android.annotation.CallSuper;
+import android.annotation.UnsupportedAppUsage;
+import android.app.ActivityTaskManager;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageParser;
+import android.content.pm.PathPermission;
+import android.content.pm.PermissionInfo;
+import android.content.pm.ProviderInfo;
+import android.content.pm.ServiceInfo;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.PatternMatcher;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.util.TypedValue;
+import android.view.Gravity;
+
+import com.android.internal.R;
+import com.android.internal.util.XmlUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.lang.reflect.Constructor;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * TODO(b/135203078): Move the inner classes out to separate files.
+ * TODO(b/135203078): Expose inner classes as immutable through interface methods.
+ *
+ * @hide
+ */
+public class ComponentParseUtils {
+
+    private static final String TAG = ApkParseUtils.TAG;
+
+    // TODO(b/135203078): None of this class's subclasses do anything. Remove in favor of base?
+    public static class ParsedIntentInfo extends IntentFilter {
+
+        /**
+         * <p>
+         * Implementation note: The serialized form for the intent list also contains the name
+         * of the concrete class that's stored in the list, and assumes that every element of the
+         * list is of the same type. This is very similar to the original parcelable mechanism.
+         * We cannot use that directly because IntentInfo extends IntentFilter, which is parcelable
+         * and is public API. It also declares Parcelable related methods as final which means
+         * we can't extend them. The approach of using composition instead of inheritance leads to
+         * a large set of cascading changes in the PackageManagerService, which seem undesirable.
+         *
+         * <p>
+         * <b>WARNING: </b> The list of objects returned by this function might need to be fixed up
+         * to make sure their owner fields are consistent. See {@code fixupOwner}.
+         */
+        public static void writeIntentsList(List<? extends ParsedIntentInfo> list, Parcel out,
+                int flags) {
+            if (list == null) {
+                out.writeInt(-1);
+                return;
+            }
+
+            final int size = list.size();
+            out.writeInt(size);
+
+            // Don't bother writing the component name if the list is empty.
+            if (size > 0) {
+                ParsedIntentInfo info = list.get(0);
+                out.writeString(info.getClass().getName());
+
+                for (int i = 0; i < size; i++) {
+                    list.get(i).writeIntentInfoToParcel(out, flags);
+                }
+            }
+        }
+
+        public static <T extends ParsedIntentInfo> ArrayList<T> createIntentsList(Parcel in) {
+            int size = in.readInt();
+            if (size == -1) {
+                return null;
+            }
+
+            if (size == 0) {
+                return new ArrayList<>(0);
+            }
+
+            String className = in.readString();
+            final ArrayList<T> intentsList;
+            try {
+                final Class<T> cls = (Class<T>) Class.forName(className);
+                final Constructor<T> cons = cls.getConstructor(Parcel.class);
+
+                intentsList = new ArrayList<>(size);
+                for (int i = 0; i < size; ++i) {
+                    intentsList.add(cons.newInstance(in));
+                }
+            } catch (ReflectiveOperationException ree) {
+                throw new AssertionError("Unable to construct intent list for: "
+                        + className, ree);
+            }
+
+            return intentsList;
+        }
+
+        protected String packageName;
+        protected final String className;
+
+        public boolean hasDefault;
+        public int labelRes;
+        public CharSequence nonLocalizedLabel;
+        public int icon;
+
+        protected List<String> rawDataTypes;
+
+        public void addRawDataType(String dataType) throws MalformedMimeTypeException {
+            if (rawDataTypes == null) {
+                rawDataTypes = new ArrayList<>();
+            }
+
+            rawDataTypes.add(dataType);
+            addDataType(dataType);
+        }
+
+        public ParsedIntentInfo(String packageName, String className) {
+            this.packageName = packageName;
+            this.className = className;
+        }
+
+        public ParsedIntentInfo(Parcel in) {
+            super(in);
+            packageName = in.readString();
+            className = in.readString();
+            hasDefault = (in.readInt() == 1);
+            labelRes = in.readInt();
+            nonLocalizedLabel = in.readCharSequence();
+            icon = in.readInt();
+        }
+
+        public void writeIntentInfoToParcel(Parcel dest, int flags) {
+            super.writeToParcel(dest, flags);
+            dest.writeString(packageName);
+            dest.writeString(className);
+            dest.writeInt(hasDefault ? 1 : 0);
+            dest.writeInt(labelRes);
+            dest.writeCharSequence(nonLocalizedLabel);
+            dest.writeInt(icon);
+        }
+
+        public String getPackageName() {
+            return packageName;
+        }
+
+        public String getClassName() {
+            return className;
+        }
+    }
+
+    public static class ParsedActivityIntentInfo extends ParsedIntentInfo {
+
+        public ParsedActivityIntentInfo(String packageName, String className) {
+            super(packageName, className);
+        }
+
+        public ParsedActivityIntentInfo(Parcel in) {
+            super(in);
+        }
+
+        public static final Creator<ParsedActivityIntentInfo> CREATOR =
+                new Creator<ParsedActivityIntentInfo>() {
+                    @Override
+                    public ParsedActivityIntentInfo createFromParcel(Parcel source) {
+                        return new ParsedActivityIntentInfo(source);
+                    }
+
+                    @Override
+                    public ParsedActivityIntentInfo[] newArray(int size) {
+                        return new ParsedActivityIntentInfo[size];
+                    }
+                };
+    }
+
+    public static class ParsedServiceIntentInfo extends ParsedIntentInfo {
+
+        public ParsedServiceIntentInfo(String packageName, String className) {
+            super(packageName, className);
+        }
+
+        public ParsedServiceIntentInfo(Parcel in) {
+            super(in);
+        }
+
+        public static final Creator<ParsedServiceIntentInfo> CREATOR =
+                new Creator<ParsedServiceIntentInfo>() {
+                    @Override
+                    public ParsedServiceIntentInfo createFromParcel(Parcel source) {
+                        return new ParsedServiceIntentInfo(source);
+                    }
+
+                    @Override
+                    public ParsedServiceIntentInfo[] newArray(int size) {
+                        return new ParsedServiceIntentInfo[size];
+                    }
+                };
+    }
+
+    public static class ParsedProviderIntentInfo extends ParsedIntentInfo {
+
+        public ParsedProviderIntentInfo(String packageName, String className) {
+            super(packageName, className);
+        }
+
+        public ParsedProviderIntentInfo(Parcel in) {
+            super(in);
+        }
+
+        public static final Creator<ParsedProviderIntentInfo> CREATOR =
+                new Creator<ParsedProviderIntentInfo>() {
+                    @Override
+                    public ParsedProviderIntentInfo createFromParcel(Parcel source) {
+                        return new ParsedProviderIntentInfo(source);
+                    }
+
+                    @Override
+                    public ParsedProviderIntentInfo[] newArray(int size) {
+                        return new ParsedProviderIntentInfo[size];
+                    }
+                };
+    }
+
+    public static class ParsedQueriesIntentInfo extends ParsedIntentInfo {
+
+        public ParsedQueriesIntentInfo(String packageName, String className) {
+            super(packageName, className);
+        }
+
+        public ParsedQueriesIntentInfo(Parcel in) {
+            super(in);
+        }
+
+        public static final Creator<ParsedQueriesIntentInfo> CREATOR =
+                new Creator<ParsedQueriesIntentInfo>() {
+                    @Override
+                    public ParsedQueriesIntentInfo createFromParcel(Parcel source) {
+                        return new ParsedQueriesIntentInfo(source);
+                    }
+
+                    @Override
+                    public ParsedQueriesIntentInfo[] newArray(int size) {
+                        return new ParsedQueriesIntentInfo[size];
+                    }
+                };
+    }
+
+    public static class ParsedComponent<IntentInfoType extends ParsedIntentInfo> implements
+            Parcelable {
+
+        // TODO(b/135203078): Replace with "name", as not all usages are an actual class
+        public String className;
+        public int icon;
+        public int labelRes;
+        public CharSequence nonLocalizedLabel;
+        public int logo;
+        public int banner;
+
+        public int descriptionRes;
+
+        // TODO(b/135203078): Make subclass that contains these fields only for the necessary
+        //  subtypes
+        protected boolean enabled = true;
+        protected boolean directBootAware;
+        public int flags;
+
+        private String packageName;
+        private String splitName;
+
+        // TODO(b/135203078): Make nullable
+        public List<IntentInfoType> intents = new ArrayList<>();
+
+        private transient ComponentName componentName;
+
+        protected Bundle metaData;
+
+        public void setSplitName(String splitName) {
+            this.splitName = splitName;
+        }
+
+        public String getSplitName() {
+            return splitName;
+        }
+
+        @CallSuper
+        public void setPackageName(String packageName) {
+            this.packageName = packageName;
+            this.componentName = null;
+        }
+
+        void setPackageNameInternal(String packageName) {
+            this.packageName = packageName;
+            this.componentName = null;
+        }
+
+        public String getPackageName() {
+            return packageName;
+        }
+
+        public final boolean isDirectBootAware() {
+            return directBootAware;
+        }
+
+        public final boolean isEnabled() {
+            return enabled;
+        }
+
+        public final String getName() {
+            return className;
+        }
+
+        public final Bundle getMetaData() {
+            return metaData;
+        }
+
+        @UnsupportedAppUsage
+        public ComponentName getComponentName() {
+            if (componentName != null) {
+                return componentName;
+            }
+            if (className != null) {
+                componentName = new ComponentName(getPackageName(),
+                        className);
+            }
+            return componentName;
+        }
+
+        public void setFrom(ParsedComponent other) {
+            this.metaData = other.metaData;
+            this.className = other.className;
+            this.icon = other.icon;
+            this.labelRes = other.labelRes;
+            this.nonLocalizedLabel = other.nonLocalizedLabel;
+            this.logo = other.logo;
+            this.banner = other.banner;
+
+            this.descriptionRes = other.descriptionRes;
+
+            this.enabled = other.enabled;
+            this.directBootAware = other.directBootAware;
+            this.flags = other.flags;
+
+            this.setPackageName(other.packageName);
+            this.setSplitName(other.getSplitName());
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeString(this.className);
+            dest.writeInt(this.icon);
+            dest.writeInt(this.labelRes);
+            dest.writeCharSequence(this.nonLocalizedLabel);
+            dest.writeInt(this.logo);
+            dest.writeInt(this.banner);
+            dest.writeInt(this.descriptionRes);
+            dest.writeBoolean(this.enabled);
+            dest.writeBoolean(this.directBootAware);
+            dest.writeInt(this.flags);
+            dest.writeString(this.packageName);
+            dest.writeString(this.splitName);
+            ParsedIntentInfo.writeIntentsList(this.intents, dest, flags);
+            dest.writeBundle(this.metaData);
+        }
+
+        public ParsedComponent() {
+        }
+
+        protected ParsedComponent(Parcel in) {
+            // We use the boot classloader for all classes that we load.
+            final ClassLoader boot = Object.class.getClassLoader();
+            this.className = in.readString();
+            this.icon = in.readInt();
+            this.labelRes = in.readInt();
+            this.nonLocalizedLabel = in.readCharSequence();
+            this.logo = in.readInt();
+            this.banner = in.readInt();
+            this.descriptionRes = in.readInt();
+            this.enabled = in.readByte() != 0;
+            this.directBootAware = in.readByte() != 0;
+            this.flags = in.readInt();
+            this.packageName = in.readString();
+            this.splitName = in.readString();
+            this.intents = ParsedIntentInfo.createIntentsList(in);
+            this.metaData = in.readBundle(boot);
+        }
+    }
+
+    // TODO(b/135203078): Document this. Maybe split out ParsedComponent to be actual components
+    //  that can have their own processes, rather than something like permission which cannot.
+    public static class ParsedMainComponent<IntentInfoType extends ParsedIntentInfo> extends
+            ParsedComponent<IntentInfoType> {
+
+        private String processName;
+        private String permission;
+
+        public void setProcessName(String appProcessName, String processName) {
+            // TODO(b/135203078): Is this even necessary anymore?
+            this.processName = TextUtils.safeIntern(
+                    processName == null ? appProcessName : processName);
+        }
+
+        public String getProcessName() {
+            return processName;
+        }
+
+        public void setPermission(String permission) {
+            this.permission = TextUtils.safeIntern(permission);
+        }
+
+        public String getPermission() {
+            return permission;
+        }
+
+        @Override
+        public void setFrom(ParsedComponent other) {
+            super.setFrom(other);
+            if (other instanceof ParsedMainComponent) {
+                ParsedMainComponent otherMainComponent = (ParsedMainComponent) other;
+                this.setProcessName(otherMainComponent.getProcessName(),
+                        otherMainComponent.getProcessName());
+                this.setPermission(otherMainComponent.getPermission());
+            }
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            super.writeToParcel(dest, flags);
+            dest.writeString(this.processName);
+            dest.writeString(this.permission);
+        }
+
+        public ParsedMainComponent() {
+        }
+
+        protected ParsedMainComponent(Parcel in) {
+            super(in);
+            this.processName = TextUtils.safeIntern(in.readString());
+            this.permission = TextUtils.safeIntern(in.readString());
+        }
+
+        public static final Creator<ParsedMainComponent> CREATOR =
+                new Creator<ParsedMainComponent>() {
+                    @Override
+                    public ParsedMainComponent createFromParcel(Parcel source) {
+                        return new ParsedMainComponent(source);
+                    }
+
+                    @Override
+                    public ParsedMainComponent[] newArray(int size) {
+                        return new ParsedMainComponent[size];
+                    }
+                };
+    }
+
+    public static class ParsedActivity extends ParsedMainComponent<ParsedActivityIntentInfo>
+            implements Parcelable {
+
+        public boolean exported;
+        public int theme;
+        public int uiOptions;
+
+        public String targetActivity;
+
+        public String parentActivityName;
+        public String taskAffinity;
+        public int privateFlags;
+
+        public int launchMode;
+        public int documentLaunchMode;
+        public int maxRecents;
+        public int configChanges;
+        public int softInputMode;
+        public int persistableMode;
+        public int lockTaskLaunchMode;
+
+        public int screenOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+        public int resizeMode = ActivityInfo.RESIZE_MODE_RESIZEABLE;
+
+        public float maxAspectRatio;
+        public boolean hasMaxAspectRatio;
+
+        public float minAspectRatio;
+        public boolean hasMinAspectRatio;
+
+        public String requestedVrComponent;
+        public int rotationAnimation = -1;
+        public int colorMode;
+        public int order;
+
+        public ActivityInfo.WindowLayout windowLayout;
+
+        @Override
+        public void setPackageName(String packageName) {
+            super.setPackageName(packageName);
+            for (ParsedIntentInfo intent : this.intents) {
+                intent.packageName = packageName;
+            }
+        }
+
+        public boolean hasMaxAspectRatio() {
+            return hasMaxAspectRatio;
+        }
+
+        public boolean hasMinAspectRatio() {
+            return hasMinAspectRatio;
+        }
+
+        public void setMaxAspectRatio(int resizeMode, float maxAspectRatio) {
+            if (resizeMode == ActivityInfo.RESIZE_MODE_RESIZEABLE
+                    || resizeMode == ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION) {
+                // Resizeable activities can be put in any aspect ratio.
+                return;
+            }
+
+            if (maxAspectRatio < 1.0f && maxAspectRatio != 0) {
+                // Ignore any value lesser than 1.0.
+                return;
+            }
+
+            this.maxAspectRatio = maxAspectRatio;
+            hasMaxAspectRatio = true;
+        }
+
+        public void setMinAspectRatio(int resizeMode, float minAspectRatio) {
+            if (resizeMode == RESIZE_MODE_RESIZEABLE
+                    || resizeMode == RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION) {
+                // Resizeable activities can be put in any aspect ratio.
+                return;
+            }
+
+            if (minAspectRatio < 1.0f && minAspectRatio != 0) {
+                // Ignore any value lesser than 1.0.
+                return;
+            }
+
+            this.minAspectRatio = minAspectRatio;
+            hasMinAspectRatio = true;
+        }
+
+        public void addIntent(ParsedActivityIntentInfo intent) {
+            this.intents.add(intent);
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            super.writeToParcel(dest, flags);
+            dest.writeBoolean(this.exported);
+            dest.writeInt(this.theme);
+            dest.writeInt(this.uiOptions);
+            dest.writeString(this.targetActivity);
+            dest.writeString(this.parentActivityName);
+            dest.writeString(this.taskAffinity);
+            dest.writeInt(this.privateFlags);
+            dest.writeInt(this.launchMode);
+            dest.writeInt(this.documentLaunchMode);
+            dest.writeInt(this.maxRecents);
+            dest.writeInt(this.configChanges);
+            dest.writeInt(this.softInputMode);
+            dest.writeInt(this.persistableMode);
+            dest.writeInt(this.lockTaskLaunchMode);
+            dest.writeInt(this.screenOrientation);
+            dest.writeInt(this.resizeMode);
+            dest.writeFloat(this.maxAspectRatio);
+            dest.writeBoolean(this.hasMaxAspectRatio);
+            dest.writeFloat(this.minAspectRatio);
+            dest.writeBoolean(this.hasMinAspectRatio);
+            dest.writeString(this.requestedVrComponent);
+            dest.writeInt(this.rotationAnimation);
+            dest.writeInt(this.colorMode);
+            dest.writeInt(this.order);
+            dest.writeBundle(this.metaData);
+
+            if (windowLayout != null) {
+                dest.writeInt(1);
+                dest.writeInt(windowLayout.width);
+                dest.writeFloat(windowLayout.widthFraction);
+                dest.writeInt(windowLayout.height);
+                dest.writeFloat(windowLayout.heightFraction);
+                dest.writeInt(windowLayout.gravity);
+                dest.writeInt(windowLayout.minWidth);
+                dest.writeInt(windowLayout.minHeight);
+            } else {
+                dest.writeInt(0);
+            }
+        }
+
+        public ParsedActivity() {
+        }
+
+        protected ParsedActivity(Parcel in) {
+            super(in);
+            this.exported = in.readByte() != 0;
+            this.theme = in.readInt();
+            this.uiOptions = in.readInt();
+            this.targetActivity = in.readString();
+            this.parentActivityName = in.readString();
+            this.taskAffinity = in.readString();
+            this.privateFlags = in.readInt();
+            this.launchMode = in.readInt();
+            this.documentLaunchMode = in.readInt();
+            this.maxRecents = in.readInt();
+            this.configChanges = in.readInt();
+            this.softInputMode = in.readInt();
+            this.persistableMode = in.readInt();
+            this.lockTaskLaunchMode = in.readInt();
+            this.screenOrientation = in.readInt();
+            this.resizeMode = in.readInt();
+            this.maxAspectRatio = in.readFloat();
+            this.hasMaxAspectRatio = in.readByte() != 0;
+            this.minAspectRatio = in.readFloat();
+            this.hasMinAspectRatio = in.readByte() != 0;
+            this.requestedVrComponent = in.readString();
+            this.rotationAnimation = in.readInt();
+            this.colorMode = in.readInt();
+            this.order = in.readInt();
+            this.metaData = in.readBundle();
+            if (in.readInt() == 1) {
+                windowLayout = new ActivityInfo.WindowLayout(in);
+            }
+        }
+
+        public static final Creator<ParsedActivity> CREATOR = new Creator<ParsedActivity>() {
+            @Override
+            public ParsedActivity createFromParcel(Parcel source) {
+                return new ParsedActivity(source);
+            }
+
+            @Override
+            public ParsedActivity[] newArray(int size) {
+                return new ParsedActivity[size];
+            }
+        };
+    }
+
+    public static class ParsedService extends ParsedMainComponent<ParsedServiceIntentInfo> {
+
+        public boolean exported;
+        public int flags;
+        public int foregroundServiceType;
+        public int order;
+
+        @Override
+        public void setPackageName(String packageName) {
+            super.setPackageName(packageName);
+            for (ParsedIntentInfo intent : this.intents) {
+                intent.packageName = packageName;
+            }
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            super.writeToParcel(dest, flags);
+            dest.writeBoolean(this.exported);
+            dest.writeBundle(this.metaData);
+            dest.writeInt(this.flags);
+            dest.writeInt(this.foregroundServiceType);
+            dest.writeInt(this.order);
+        }
+
+        public ParsedService() {
+        }
+
+        protected ParsedService(Parcel in) {
+            super(in);
+            this.exported = in.readByte() != 0;
+            this.metaData = in.readBundle();
+            this.flags = in.readInt();
+            this.foregroundServiceType = in.readInt();
+            this.order = in.readInt();
+        }
+
+        public static final Creator<ParsedService> CREATOR = new Creator<ParsedService>() {
+            @Override
+            public ParsedService createFromParcel(Parcel source) {
+                return new ParsedService(source);
+            }
+
+            @Override
+            public ParsedService[] newArray(int size) {
+                return new ParsedService[size];
+            }
+        };
+    }
+
+    public static class ParsedProvider extends ParsedMainComponent<ParsedProviderIntentInfo> {
+
+        protected boolean exported;
+        protected int flags;
+        protected int order;
+        private String authority;
+        protected boolean isSyncable;
+        private String readPermission;
+        private String writePermission;
+        protected boolean grantUriPermissions;
+        protected boolean forceUriPermissions;
+        protected boolean multiProcess;
+        protected int initOrder;
+        protected PatternMatcher[] uriPermissionPatterns;
+        protected PathPermission[] pathPermissions;
+
+        protected void setFrom(ParsedProvider other) {
+            super.setFrom(other);
+            this.exported = other.exported;
+
+            this.intents.clear();
+            if (other.intents != null) {
+                this.intents.addAll(other.intents);
+            }
+
+            this.flags = other.flags;
+            this.order = other.order;
+            this.setAuthority(other.getAuthority());
+            this.isSyncable = other.isSyncable;
+            this.setReadPermission(other.getReadPermission());
+            this.setWritePermission(other.getWritePermission());
+            this.grantUriPermissions = other.grantUriPermissions;
+            this.forceUriPermissions = other.forceUriPermissions;
+            this.multiProcess = other.multiProcess;
+            this.initOrder = other.initOrder;
+            this.uriPermissionPatterns = other.uriPermissionPatterns;
+            this.pathPermissions = other.pathPermissions;
+        }
+
+        @Override
+        public void setPackageName(String packageName) {
+            super.setPackageName(packageName);
+            for (ParsedIntentInfo intent : this.intents) {
+                intent.packageName = packageName;
+            }
+        }
+
+        public boolean isExported() {
+            return exported;
+        }
+
+        public List<ParsedProviderIntentInfo> getIntents() {
+            return intents;
+        }
+
+        public int getFlags() {
+            return flags;
+        }
+
+        public int getOrder() {
+            return order;
+        }
+
+        public void setAuthority(String authority) {
+            this.authority = TextUtils.safeIntern(authority);
+        }
+
+        public String getAuthority() {
+            return authority;
+        }
+
+        public boolean isSyncable() {
+            return isSyncable;
+        }
+
+        public void setReadPermission(String readPermission) {
+            this.readPermission = TextUtils.safeIntern(readPermission);
+        }
+
+        public String getReadPermission() {
+            return readPermission;
+        }
+
+        public void setWritePermission(String writePermission) {
+            this.writePermission = TextUtils.safeIntern(writePermission);
+        }
+
+        public String getWritePermission() {
+            return writePermission;
+        }
+
+        public boolean isGrantUriPermissions() {
+            return grantUriPermissions;
+        }
+
+        public boolean isForceUriPermissions() {
+            return forceUriPermissions;
+        }
+
+        public boolean isMultiProcess() {
+            return multiProcess;
+        }
+
+        public int getInitOrder() {
+            return initOrder;
+        }
+
+        public PatternMatcher[] getUriPermissionPatterns() {
+            return uriPermissionPatterns;
+        }
+
+        public PathPermission[] getPathPermissions() {
+            return pathPermissions;
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            super.writeToParcel(dest, flags);
+            dest.writeBoolean(this.exported);
+            dest.writeInt(this.flags);
+            dest.writeInt(this.order);
+            dest.writeString(this.authority);
+            dest.writeBoolean(this.isSyncable);
+            dest.writeString(this.readPermission);
+            dest.writeString(this.writePermission);
+            dest.writeBoolean(this.grantUriPermissions);
+            dest.writeBoolean(this.forceUriPermissions);
+            dest.writeBoolean(this.multiProcess);
+            dest.writeInt(this.initOrder);
+            dest.writeTypedArray(this.uriPermissionPatterns, flags);
+            dest.writeTypedArray(this.pathPermissions, flags);
+        }
+
+        public ParsedProvider() {
+        }
+
+        protected ParsedProvider(Parcel in) {
+            super(in);
+            this.exported = in.readByte() != 0;
+            this.flags = in.readInt();
+            this.order = in.readInt();
+            this.authority = TextUtils.safeIntern(in.readString());
+            this.isSyncable = in.readByte() != 0;
+            this.readPermission = TextUtils.safeIntern(in.readString());
+            this.writePermission = TextUtils.safeIntern(in.readString());
+            this.grantUriPermissions = in.readByte() != 0;
+            this.forceUriPermissions = in.readByte() != 0;
+            this.multiProcess = in.readByte() != 0;
+            this.initOrder = in.readInt();
+            this.uriPermissionPatterns = in.createTypedArray(PatternMatcher.CREATOR);
+            this.pathPermissions = in.createTypedArray(PathPermission.CREATOR);
+        }
+
+        public static final Creator<ParsedProvider> CREATOR = new Creator<ParsedProvider>() {
+            @Override
+            public ParsedProvider createFromParcel(Parcel source) {
+                return new ParsedProvider(source);
+            }
+
+            @Override
+            public ParsedProvider[] newArray(int size) {
+                return new ParsedProvider[size];
+            }
+        };
+    }
+
+    public static class ParsedPermission extends ParsedComponent<ParsedIntentInfo> {
+
+        public String backgroundPermission;
+        private String group;
+        public int requestRes;
+        public int protectionLevel;
+        public boolean tree;
+
+        public ParsedPermissionGroup parsedPermissionGroup;
+
+        public void setName(String className) {
+            this.className = className;
+        }
+
+        public void setGroup(String group) {
+            this.group = TextUtils.safeIntern(group);
+        }
+
+        public String getGroup() {
+            return group;
+        }
+
+        public boolean isRuntime() {
+            return protectionLevel == PermissionInfo.PROTECTION_DANGEROUS;
+        }
+
+        public boolean isAppOp() {
+            return (protectionLevel & PermissionInfo.PROTECTION_FLAG_APPOP) != 0;
+        }
+
+        @PermissionInfo.Protection
+        public int getProtection() {
+            return protectionLevel & PermissionInfo.PROTECTION_MASK_BASE;
+        }
+
+        public int getProtectionFlags() {
+            return protectionLevel & ~PermissionInfo.PROTECTION_MASK_BASE;
+        }
+
+        public int calculateFootprint() {
+            int size = getName().length();
+            if (nonLocalizedLabel != null) {
+                size += nonLocalizedLabel.length();
+            }
+            return size;
+        }
+
+        public ParsedPermission() {
+        }
+
+        public ParsedPermission(ParsedPermission other) {
+            // TODO(b/135203078): Better way to copy this? Maybe refactor to the point where copy
+            //  isn't needed.
+            this.className = other.className;
+            this.icon = other.icon;
+            this.labelRes = other.labelRes;
+            this.nonLocalizedLabel = other.nonLocalizedLabel;
+            this.logo = other.logo;
+            this.banner = other.banner;
+            this.descriptionRes = other.descriptionRes;
+            this.enabled = other.enabled;
+            this.directBootAware = other.directBootAware;
+            this.flags = other.flags;
+            this.setSplitName(other.getSplitName());
+            this.setPackageName(other.getPackageName());
+
+            this.intents.addAll(other.intents);
+
+            if (other.metaData != null) {
+                this.metaData = new Bundle();
+                this.metaData.putAll(other.metaData);
+            }
+
+            this.backgroundPermission = other.backgroundPermission;
+            this.setGroup(other.group);
+            this.requestRes = other.requestRes;
+            this.protectionLevel = other.protectionLevel;
+            this.tree = other.tree;
+
+            this.parsedPermissionGroup = other.parsedPermissionGroup;
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            super.writeToParcel(dest, flags);
+            dest.writeString(this.backgroundPermission);
+            dest.writeString(this.group);
+            dest.writeInt(this.requestRes);
+            dest.writeInt(this.protectionLevel);
+            dest.writeBoolean(this.tree);
+            dest.writeParcelable(this.parsedPermissionGroup, flags);
+        }
+
+        protected ParsedPermission(Parcel in) {
+            super(in);
+            // We use the boot classloader for all classes that we load.
+            final ClassLoader boot = Object.class.getClassLoader();
+            this.backgroundPermission = in.readString();
+            this.group = TextUtils.safeIntern(in.readString());
+            this.requestRes = in.readInt();
+            this.protectionLevel = in.readInt();
+            this.tree = in.readBoolean();
+            this.parsedPermissionGroup = in.readParcelable(boot);
+        }
+
+        public static final Creator<ParsedPermission> CREATOR = new Creator<ParsedPermission>() {
+            @Override
+            public ParsedPermission createFromParcel(Parcel source) {
+                return new ParsedPermission(source);
+            }
+
+            @Override
+            public ParsedPermission[] newArray(int size) {
+                return new ParsedPermission[size];
+            }
+        };
+    }
+
+    public static class ParsedPermissionGroup extends ParsedComponent<ParsedIntentInfo> {
+
+        public int requestDetailResourceId;
+        public int backgroundRequestResourceId;
+        public int backgroundRequestDetailResourceId;
+
+        public int requestRes;
+        public int priority;
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            super.writeToParcel(dest, flags);
+            dest.writeInt(this.requestDetailResourceId);
+            dest.writeInt(this.backgroundRequestResourceId);
+            dest.writeInt(this.backgroundRequestDetailResourceId);
+            dest.writeInt(this.requestRes);
+            dest.writeInt(this.priority);
+        }
+
+        public ParsedPermissionGroup() {
+        }
+
+        protected ParsedPermissionGroup(Parcel in) {
+            super(in);
+            this.requestDetailResourceId = in.readInt();
+            this.backgroundRequestResourceId = in.readInt();
+            this.backgroundRequestDetailResourceId = in.readInt();
+            this.requestRes = in.readInt();
+            this.priority = in.readInt();
+        }
+
+        public static final Creator<ParsedPermissionGroup> CREATOR =
+                new Creator<ParsedPermissionGroup>() {
+                    @Override
+                    public ParsedPermissionGroup createFromParcel(Parcel source) {
+                        return new ParsedPermissionGroup(source);
+                    }
+
+                    @Override
+                    public ParsedPermissionGroup[] newArray(int size) {
+                        return new ParsedPermissionGroup[size];
+                    }
+                };
+    }
+
+    public static class ParsedInstrumentation extends ParsedComponent<ParsedIntentInfo> {
+
+        private String targetPackage;
+        private String targetProcesses;
+        public boolean handleProfiling;
+        public boolean functionalTest;
+
+        public String sourceDir;
+        public String publicSourceDir;
+        public String[] splitNames;
+        public String[] splitSourceDirs;
+        public String[] splitPublicSourceDirs;
+        public SparseArray<int[]> splitDependencies;
+        public String dataDir;
+        public String deviceProtectedDataDir;
+        public String credentialProtectedDataDir;
+        public String primaryCpuAbi;
+        public String secondaryCpuAbi;
+        public String nativeLibraryDir;
+        public String secondaryNativeLibraryDir;
+
+        public ParsedInstrumentation() {
+        }
+
+        public void setTargetPackage(String targetPackage) {
+            this.targetPackage = TextUtils.safeIntern(targetPackage);
+        }
+
+        public String getTargetPackage() {
+            return targetPackage;
+        }
+
+        public void setTargetProcesses(String targetProcesses) {
+            this.targetProcesses = TextUtils.safeIntern(targetProcesses);
+        }
+
+        public String getTargetProcesses() {
+            return targetProcesses;
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            super.writeToParcel(dest, flags);
+            dest.writeString(this.targetPackage);
+            dest.writeString(this.targetProcesses);
+            dest.writeBoolean(this.handleProfiling);
+            dest.writeBoolean(this.functionalTest);
+            dest.writeString(this.sourceDir);
+            dest.writeString(this.publicSourceDir);
+            dest.writeStringArray(this.splitNames);
+            dest.writeStringArray(this.splitSourceDirs);
+            dest.writeStringArray(this.splitPublicSourceDirs);
+            dest.writeSparseArray(this.splitDependencies);
+            dest.writeString(this.dataDir);
+            dest.writeString(this.deviceProtectedDataDir);
+            dest.writeString(this.credentialProtectedDataDir);
+            dest.writeString(this.primaryCpuAbi);
+            dest.writeString(this.secondaryCpuAbi);
+            dest.writeString(this.nativeLibraryDir);
+            dest.writeString(this.secondaryNativeLibraryDir);
+        }
+
+        protected ParsedInstrumentation(Parcel in) {
+            super(in);
+            // We use the boot classloader for all classes that we load.
+            final ClassLoader boot = Object.class.getClassLoader();
+            this.targetPackage = TextUtils.safeIntern(in.readString());
+            this.targetProcesses = TextUtils.safeIntern(in.readString());
+            this.handleProfiling = in.readByte() != 0;
+            this.functionalTest = in.readByte() != 0;
+            this.sourceDir = in.readString();
+            this.publicSourceDir = in.readString();
+            this.splitNames = in.createStringArray();
+            this.splitSourceDirs = in.createStringArray();
+            this.splitPublicSourceDirs = in.createStringArray();
+            this.splitDependencies = in.readSparseArray(boot);
+            this.dataDir = in.readString();
+            this.deviceProtectedDataDir = in.readString();
+            this.credentialProtectedDataDir = in.readString();
+            this.primaryCpuAbi = in.readString();
+            this.secondaryCpuAbi = in.readString();
+            this.nativeLibraryDir = in.readString();
+            this.secondaryNativeLibraryDir = in.readString();
+        }
+
+        public static final Creator<ParsedInstrumentation> CREATOR =
+                new Creator<ParsedInstrumentation>() {
+                    @Override
+                    public ParsedInstrumentation createFromParcel(Parcel source) {
+                        return new ParsedInstrumentation(source);
+                    }
+
+                    @Override
+                    public ParsedInstrumentation[] newArray(int size) {
+                        return new ParsedInstrumentation[size];
+                    }
+                };
+    }
+
+    public static ParsedActivity parseActivity(
+            String[] separateProcesses,
+            ParsingPackage parsingPackage,
+            Resources res,
+            XmlResourceParser parser, int flags, String[] outError,
+            boolean receiver, boolean hardwareAccelerated)
+            throws XmlPullParserException, IOException {
+
+        TypedArray sa = null;
+        boolean visibleToEphemeral;
+        boolean setExported;
+
+        int targetSdkVersion = parsingPackage.getTargetSdkVersion();
+        String packageName = parsingPackage.getPackageName();
+        String packageProcessName = parsingPackage.getProcessName();
+        ParsedActivity result = new ParsedActivity();
+
+        try {
+            sa = res.obtainAttributes(parser, R.styleable.AndroidManifestActivity);
+
+            String tag = receiver ? "<receiver>" : "<activity>";
+
+            String name = sa.getNonConfigurationString(R.styleable.AndroidManifestActivity_name, 0);
+            if (name == null) {
+                outError[0] = tag + " does not specify android:name";
+                return null;
+            } else {
+                String className = ApkParseUtils.buildClassName(packageName, name);
+                if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) {
+                    outError[0] = tag + " invalid android:name";
+                    return null;
+                } else if (className == null) {
+                    outError[0] = "Empty class name in package " + packageName;
+                    return null;
+                }
+
+                result.className = className;
+            }
+
+            int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId(
+                    R.styleable.AndroidManifestActivity_roundIcon, 0) : 0;
+            if (roundIconVal != 0) {
+                result.icon = roundIconVal;
+                result.nonLocalizedLabel = null;
+            } else {
+                int iconVal = sa.getResourceId(R.styleable.AndroidManifestActivity_icon, 0);
+                if (iconVal != 0) {
+                    result.icon = iconVal;
+                    result.nonLocalizedLabel = null;
+                }
+            }
+
+            int logoVal = sa.getResourceId(R.styleable.AndroidManifestActivity_logo, 0);
+            if (logoVal != 0) {
+                result.logo = logoVal;
+            }
+
+            int bannerVal = sa.getResourceId(R.styleable.AndroidManifestActivity_banner, 0);
+            if (bannerVal != 0) {
+                result.banner = bannerVal;
+            }
+
+            TypedValue v = sa.peekValue(R.styleable.AndroidManifestActivity_label);
+            if (v != null && (result.labelRes = v.resourceId) == 0) {
+                result.nonLocalizedLabel = v.coerceToString();
+            }
+
+            result.setPackageNameInternal(packageName);
+
+            CharSequence pname;
+            if (parsingPackage.getTargetSdkVersion() >= Build.VERSION_CODES.FROYO) {
+                pname = sa.getNonConfigurationString(R.styleable.AndroidManifestActivity_process,
+                        Configuration.NATIVE_CONFIG_VERSION);
+            } else {
+                // Some older apps have been seen to use a resource reference
+                // here that on older builds was ignored (with a warning).  We
+                // need to continue to do this for them so they don't break.
+                pname = sa.getNonResourceString(R.styleable.AndroidManifestActivity_process);
+            }
+
+            result.setProcessName(packageProcessName, PackageParser.buildProcessName(packageName,
+                    packageProcessName, pname,
+                    flags, separateProcesses, outError));
+
+            result.descriptionRes = sa.getResourceId(
+                    R.styleable.AndroidManifestActivity_description, 0);
+
+            result.enabled = sa.getBoolean(R.styleable.AndroidManifestActivity_enabled, true);
+
+            setExported = sa.hasValue(R.styleable.AndroidManifestActivity_exported);
+            if (setExported) {
+                result.exported = sa.getBoolean(R.styleable.AndroidManifestActivity_exported,
+                        false);
+            }
+
+            result.theme = sa.getResourceId(R.styleable.AndroidManifestActivity_theme, 0);
+
+            result.uiOptions = sa.getInt(R.styleable.AndroidManifestActivity_uiOptions,
+                    parsingPackage.getUiOptions());
+
+            String parentName = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestActivity_parentActivityName,
+                    Configuration.NATIVE_CONFIG_VERSION);
+            if (parentName != null) {
+                String parentClassName = ApkParseUtils.buildClassName(packageName, parentName);
+                if (parentClassName == null) {
+                    Log.e(TAG,
+                            "Activity " + result.className
+                                    + " specified invalid parentActivityName " +
+                                    parentName);
+                } else {
+                    result.parentActivityName = parentClassName;
+                }
+            }
+
+            String str;
+            str = sa.getNonConfigurationString(R.styleable.AndroidManifestActivity_permission, 0);
+            if (str == null) {
+                result.setPermission(parsingPackage.getPermission());
+            } else {
+                result.setPermission(str);
+            }
+
+            str = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestActivity_taskAffinity,
+                    Configuration.NATIVE_CONFIG_VERSION);
+            result.taskAffinity = PackageParser.buildTaskAffinityName(
+                    packageName,
+                    parsingPackage.getTaskAffinity(), str, outError);
+
+            result.setSplitName(
+                    sa.getNonConfigurationString(R.styleable.AndroidManifestActivity_splitName, 0));
+
+            result.flags = 0;
+            if (sa.getBoolean(
+                    R.styleable.AndroidManifestActivity_multiprocess, false)) {
+                result.flags |= ActivityInfo.FLAG_MULTIPROCESS;
+            }
+
+            if (sa.getBoolean(R.styleable.AndroidManifestActivity_finishOnTaskLaunch, false)) {
+                result.flags |= ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH;
+            }
+
+            if (sa.getBoolean(R.styleable.AndroidManifestActivity_clearTaskOnLaunch, false)) {
+                result.flags |= ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH;
+            }
+
+            if (sa.getBoolean(R.styleable.AndroidManifestActivity_noHistory, false)) {
+                result.flags |= ActivityInfo.FLAG_NO_HISTORY;
+            }
+
+            if (sa.getBoolean(R.styleable.AndroidManifestActivity_alwaysRetainTaskState, false)) {
+                result.flags |= ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE;
+            }
+
+            if (sa.getBoolean(R.styleable.AndroidManifestActivity_stateNotNeeded, false)) {
+                result.flags |= ActivityInfo.FLAG_STATE_NOT_NEEDED;
+            }
+
+            if (sa.getBoolean(R.styleable.AndroidManifestActivity_excludeFromRecents, false)) {
+                result.flags |= ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
+            }
+
+            if (sa.getBoolean(R.styleable.AndroidManifestActivity_allowTaskReparenting,
+                    (parsingPackage.getFlags() & ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING)
+                            != 0)) {
+                result.flags |= ActivityInfo.FLAG_ALLOW_TASK_REPARENTING;
+            }
+
+            if (sa.getBoolean(R.styleable.AndroidManifestActivity_finishOnCloseSystemDialogs,
+                    false)) {
+                result.flags |= ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS;
+            }
+
+            if (sa.getBoolean(R.styleable.AndroidManifestActivity_showOnLockScreen, false)
+                    || sa.getBoolean(R.styleable.AndroidManifestActivity_showForAllUsers, false)) {
+                result.flags |= ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
+            }
+
+            if (sa.getBoolean(R.styleable.AndroidManifestActivity_immersive, false)) {
+                result.flags |= ActivityInfo.FLAG_IMMERSIVE;
+            }
+
+            if (sa.getBoolean(R.styleable.AndroidManifestActivity_systemUserOnly, false)) {
+                result.flags |= ActivityInfo.FLAG_SYSTEM_USER_ONLY;
+            }
+
+            boolean directBootAware;
+
+            if (!receiver) {
+                if (sa.getBoolean(R.styleable.AndroidManifestActivity_hardwareAccelerated,
+                        hardwareAccelerated)) {
+                    result.flags |= ActivityInfo.FLAG_HARDWARE_ACCELERATED;
+                }
+
+                result.launchMode = sa.getInt(
+                        R.styleable.AndroidManifestActivity_launchMode,
+                        ActivityInfo.LAUNCH_MULTIPLE);
+                result.documentLaunchMode = sa.getInt(
+                        R.styleable.AndroidManifestActivity_documentLaunchMode,
+                        ActivityInfo.DOCUMENT_LAUNCH_NONE);
+                result.maxRecents = sa.getInt(
+                        R.styleable.AndroidManifestActivity_maxRecents,
+                        ActivityTaskManager.getDefaultAppRecentsLimitStatic());
+                result.configChanges = PackageParser.getActivityConfigChanges(
+                        sa.getInt(R.styleable.AndroidManifestActivity_configChanges, 0),
+                        sa.getInt(R.styleable.AndroidManifestActivity_recreateOnConfigChanges, 0));
+                result.softInputMode = sa.getInt(
+                        R.styleable.AndroidManifestActivity_windowSoftInputMode, 0);
+
+                result.persistableMode = sa.getInteger(
+                        R.styleable.AndroidManifestActivity_persistableMode,
+                        ActivityInfo.PERSIST_ROOT_ONLY);
+
+                if (sa.getBoolean(R.styleable.AndroidManifestActivity_allowEmbedded, false)) {
+                    result.flags |= ActivityInfo.FLAG_ALLOW_EMBEDDED;
+                }
+
+                if (sa.getBoolean(R.styleable.AndroidManifestActivity_autoRemoveFromRecents,
+                        false)) {
+                    result.flags |= ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS;
+                }
+
+                if (sa.getBoolean(R.styleable.AndroidManifestActivity_relinquishTaskIdentity,
+                        false)) {
+                    result.flags |= ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY;
+                }
+
+                if (sa.getBoolean(R.styleable.AndroidManifestActivity_resumeWhilePausing, false)) {
+                    result.flags |= ActivityInfo.FLAG_RESUME_WHILE_PAUSING;
+                }
+
+                int screenOrientation = sa.getInt(
+                        R.styleable.AndroidManifestActivity_screenOrientation,
+                        SCREEN_ORIENTATION_UNSPECIFIED);
+                result.screenOrientation = screenOrientation;
+
+                int resizeMode = getActivityResizeMode(parsingPackage, sa, screenOrientation);
+                result.resizeMode = resizeMode;
+
+                if (sa.getBoolean(R.styleable.AndroidManifestActivity_supportsPictureInPicture,
+                        false)) {
+                    result.flags |= FLAG_SUPPORTS_PICTURE_IN_PICTURE;
+                }
+
+                if (sa.getBoolean(R.styleable.AndroidManifestActivity_alwaysFocusable, false)) {
+                    result.flags |= FLAG_ALWAYS_FOCUSABLE;
+                }
+
+                if (sa.hasValue(R.styleable.AndroidManifestActivity_maxAspectRatio)
+                        && sa.getType(R.styleable.AndroidManifestActivity_maxAspectRatio)
+                        == TypedValue.TYPE_FLOAT) {
+                    result.setMaxAspectRatio(resizeMode,
+                            sa.getFloat(R.styleable.AndroidManifestActivity_maxAspectRatio,
+                                    0 /*default*/));
+                }
+
+                if (sa.hasValue(R.styleable.AndroidManifestActivity_minAspectRatio)
+                        && sa.getType(R.styleable.AndroidManifestActivity_minAspectRatio)
+                        == TypedValue.TYPE_FLOAT) {
+                    result.setMinAspectRatio(resizeMode,
+                            sa.getFloat(R.styleable.AndroidManifestActivity_minAspectRatio,
+                                    0 /*default*/));
+                }
+
+                result.lockTaskLaunchMode =
+                        sa.getInt(R.styleable.AndroidManifestActivity_lockTaskMode, 0);
+
+                directBootAware = sa.getBoolean(
+                        R.styleable.AndroidManifestActivity_directBootAware,
+                        false);
+
+                result.requestedVrComponent =
+                        sa.getString(R.styleable.AndroidManifestActivity_enableVrMode);
+
+                result.rotationAnimation =
+                        sa.getInt(R.styleable.AndroidManifestActivity_rotationAnimation,
+                                ROTATION_ANIMATION_UNSPECIFIED);
+
+                result.colorMode = sa.getInt(R.styleable.AndroidManifestActivity_colorMode,
+                        ActivityInfo.COLOR_MODE_DEFAULT);
+
+                if (sa.getBoolean(R.styleable.AndroidManifestActivity_showWhenLocked, false)) {
+                    result.flags |= ActivityInfo.FLAG_SHOW_WHEN_LOCKED;
+                }
+
+                if (sa.getBoolean(R.styleable.AndroidManifestActivity_turnScreenOn, false)) {
+                    result.flags |= ActivityInfo.FLAG_TURN_SCREEN_ON;
+                }
+
+                if (sa.getBoolean(R.styleable.AndroidManifestActivity_inheritShowWhenLocked,
+                        false)) {
+                    result.privateFlags |= ActivityInfo.FLAG_INHERIT_SHOW_WHEN_LOCKED;
+                }
+            } else {
+                result.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
+                result.configChanges = 0;
+
+                if (sa.getBoolean(R.styleable.AndroidManifestActivity_singleUser, false)) {
+                    result.flags |= ActivityInfo.FLAG_SINGLE_USER;
+                }
+                directBootAware = sa.getBoolean(
+                        R.styleable.AndroidManifestActivity_directBootAware,
+                        false);
+            }
+
+            result.directBootAware = directBootAware;
+
+            if (directBootAware) {
+                parsingPackage.setPartiallyDirectBootAware(true);
+            }
+
+            // can't make this final; we may set it later via meta-data
+            visibleToEphemeral = sa.getBoolean(
+                    R.styleable.AndroidManifestActivity_visibleToInstantApps, false);
+            if (visibleToEphemeral) {
+                result.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP;
+                parsingPackage.setVisibleToInstantApps(true);
+            }
+        } finally {
+            if (sa != null) {
+                sa.recycle();
+            }
+        }
+
+
+        if (receiver && (parsingPackage.getPrivateFlags()
+                & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) {
+            // A heavy-weight application can not have receives in its main process
+            if (result.getProcessName().equals(packageName)) {
+                outError[0] = "Heavy-weight applications can not have receivers in main process";
+                return null;
+            }
+        }
+
+        if (outError[0] != null) {
+            return null;
+        }
+
+        int outerDepth = parser.getDepth();
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG
+                || parser.getDepth() > outerDepth)) {
+            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                continue;
+            }
+
+            if (parser.getName().equals("intent-filter")) {
+                ParsedActivityIntentInfo intentInfo = new ParsedActivityIntentInfo(packageName,
+                        result.className);
+                if (!parseIntentInfo(intentInfo, parsingPackage, res, parser,
+                        true /*allowGlobs*/,
+                        true /*allowAutoVerify*/, outError)) {
+                    return null;
+                }
+                if (intentInfo.countActions() == 0) {
+                    Slog.w(TAG, "No actions in intent filter at "
+                            + parsingPackage.getBaseCodePath() + " "
+                            + parser.getPositionDescription());
+                } else {
+                    result.order = Math.max(intentInfo.getOrder(), result.order);
+                    result.addIntent(intentInfo);
+                }
+                // adjust activity flags when we implicitly expose it via a browsable filter
+                final int visibility = visibleToEphemeral
+                        ? IntentFilter.VISIBILITY_EXPLICIT
+                        : !receiver && isImplicitlyExposedIntent(intentInfo)
+                                ? IntentFilter.VISIBILITY_IMPLICIT
+                                : IntentFilter.VISIBILITY_NONE;
+                intentInfo.setVisibilityToInstantApp(visibility);
+                if (intentInfo.isVisibleToInstantApp()) {
+                    result.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP;
+                }
+                if (intentInfo.isImplicitlyVisibleToInstantApp()) {
+                    result.flags |= ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP;
+                }
+                if (PackageParser.LOG_UNSAFE_BROADCASTS && receiver
+                        && (targetSdkVersion >= Build.VERSION_CODES.O)) {
+                    for (int i = 0; i < intentInfo.countActions(); i++) {
+                        final String action = intentInfo.getAction(i);
+                        if (action == null || !action.startsWith("android.")) continue;
+                        if (!PackageParser.SAFE_BROADCASTS.contains(action)) {
+                            Slog.w(TAG, "Broadcast " + action + " may never be delivered to "
+                                    + packageName + " as requested at: "
+                                    + parser.getPositionDescription());
+                        }
+                    }
+                }
+            } else if (!receiver && parser.getName().equals("preferred")) {
+                ParsedActivityIntentInfo intentInfo = new ParsedActivityIntentInfo(packageName,
+                        result.className);
+                if (!parseIntentInfo(intentInfo, parsingPackage, res, parser,
+                        false /*allowGlobs*/,
+                        false /*allowAutoVerify*/, outError)) {
+                    return null;
+                }
+                // adjust activity flags when we implicitly expose it via a browsable filter
+                final int visibility = visibleToEphemeral
+                        ? IntentFilter.VISIBILITY_EXPLICIT
+                        : !receiver && isImplicitlyExposedIntent(intentInfo)
+                                ? IntentFilter.VISIBILITY_IMPLICIT
+                                : IntentFilter.VISIBILITY_NONE;
+                intentInfo.setVisibilityToInstantApp(visibility);
+                if (intentInfo.isVisibleToInstantApp()) {
+                    result.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP;
+                }
+                if (intentInfo.isImplicitlyVisibleToInstantApp()) {
+                    result.flags |= ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP;
+                }
+
+                if (intentInfo.countActions() == 0) {
+                    Slog.w(TAG, "No actions in preferred at "
+                            + parsingPackage.getBaseCodePath() + " "
+                            + parser.getPositionDescription());
+                } else {
+                    parsingPackage.addPreferredActivityFilter(intentInfo);
+                }
+            } else if (parser.getName().equals("meta-data")) {
+                if ((result.metaData = ApkParseUtils.parseMetaData(parsingPackage, res, parser,
+                        result.metaData,
+                        outError)) == null) {
+                    return null;
+                }
+            } else if (!receiver && parser.getName().equals("layout")) {
+                result.windowLayout = parseLayout(res, parser);
+            } else {
+                if (!PackageParser.RIGID_PARSER) {
+                    Slog.w(TAG, "Problem in package " + parsingPackage.getBaseCodePath() + ":");
+                    if (receiver) {
+                        Slog.w(TAG, "Unknown element under <receiver>: " + parser.getName()
+                                + " at " + parsingPackage.getBaseCodePath() + " "
+                                + parser.getPositionDescription());
+                    } else {
+                        Slog.w(TAG, "Unknown element under <activity>: " + parser.getName()
+                                + " at " + parsingPackage.getBaseCodePath() + " "
+                                + parser.getPositionDescription());
+                    }
+                    XmlUtils.skipCurrentTag(parser);
+                    continue;
+                } else {
+                    if (receiver) {
+                        outError[0] = "Bad element under <receiver>: " + parser.getName();
+                    } else {
+                        outError[0] = "Bad element under <activity>: " + parser.getName();
+                    }
+                    return null;
+                }
+            }
+        }
+
+        if (!setExported) {
+            result.exported = result.intents.size() > 0;
+        }
+
+        return result;
+    }
+
+    public static boolean isImplicitlyExposedIntent(ParsedIntentInfo intentInfo) {
+        return intentInfo.hasCategory(Intent.CATEGORY_BROWSABLE)
+                || intentInfo.hasAction(Intent.ACTION_SEND)
+                || intentInfo.hasAction(Intent.ACTION_SENDTO)
+                || intentInfo.hasAction(Intent.ACTION_SEND_MULTIPLE);
+    }
+
+    public static int getActivityResizeMode(
+            ParsingPackage parsingPackage,
+            TypedArray sa,
+            int screenOrientation
+    ) {
+        int privateFlags = parsingPackage.getPrivateFlags();
+        final boolean appExplicitDefault = (privateFlags
+                & (ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE
+                | ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE)) != 0;
+
+        if (sa.hasValue(R.styleable.AndroidManifestActivity_resizeableActivity)
+                || appExplicitDefault) {
+            // Activity or app explicitly set if it is resizeable or not;
+            final boolean appResizeable = (privateFlags
+                    & ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE) != 0;
+            if (sa.getBoolean(R.styleable.AndroidManifestActivity_resizeableActivity,
+                    appResizeable)) {
+                return ActivityInfo.RESIZE_MODE_RESIZEABLE;
+            } else {
+                return ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
+            }
+        }
+
+        if ((privateFlags
+                & ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION)
+                != 0) {
+            // The activity or app didn't explicitly set the resizing option, however we want to
+            // make it resize due to the sdk version it is targeting.
+            return ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
+        }
+
+        // resize preference isn't set and target sdk version doesn't support resizing apps by
+        // default. For the app to be resizeable if it isn't fixed orientation or immersive.
+        if (ActivityInfo.isFixedOrientationPortrait(screenOrientation)) {
+            return ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY;
+        } else if (ActivityInfo.isFixedOrientationLandscape(screenOrientation)) {
+            return ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY;
+        } else if (screenOrientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED) {
+            return ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION;
+        } else {
+            return ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE;
+        }
+    }
+
+    public static ParsedService parseService(
+            String[] separateProcesses,
+            ParsingPackage parsingPackage,
+            Resources res,
+            XmlResourceParser parser, int flags, String[] outError
+    ) throws XmlPullParserException, IOException {
+        TypedArray sa = null;
+        boolean visibleToEphemeral;
+        boolean setExported;
+
+        String packageName = parsingPackage.getPackageName();
+        String packageProcessName = parsingPackage.getProcessName();
+        ParsedService result = new ParsedService();
+
+        try {
+            sa = res.obtainAttributes(parser,
+                    R.styleable.AndroidManifestService);
+
+            String name = sa.getNonConfigurationString(R.styleable.AndroidManifestService_name, 0);
+            if (name == null) {
+                outError[0] = "<service> does not specify android:name";
+                return null;
+            } else {
+                String className = ApkParseUtils.buildClassName(packageName, name);
+                if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) {
+                    outError[0] = "<service> invalid android:name";
+                    return null;
+                } else if (className == null) {
+                    outError[0] = "Empty class name in package " + packageName;
+                    return null;
+                }
+
+                result.className = className;
+            }
+
+            int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId(
+                    R.styleable.AndroidManifestService_roundIcon, 0) : 0;
+            if (roundIconVal != 0) {
+                result.icon = roundIconVal;
+                result.nonLocalizedLabel = null;
+            } else {
+                int iconVal = sa.getResourceId(R.styleable.AndroidManifestService_icon, 0);
+                if (iconVal != 0) {
+                    result.icon = iconVal;
+                    result.nonLocalizedLabel = null;
+                }
+            }
+
+            int logoVal = sa.getResourceId(R.styleable.AndroidManifestService_logo, 0);
+            if (logoVal != 0) {
+                result.logo = logoVal;
+            }
+
+            int bannerVal = sa.getResourceId(R.styleable.AndroidManifestService_banner, 0);
+            if (bannerVal != 0) {
+                result.banner = bannerVal;
+            }
+
+            TypedValue v = sa.peekValue(R.styleable.AndroidManifestService_label);
+            if (v != null && (result.labelRes = v.resourceId) == 0) {
+                result.nonLocalizedLabel = v.coerceToString();
+            }
+
+            result.setPackageNameInternal(packageName);
+
+            CharSequence pname;
+            if (parsingPackage.getTargetSdkVersion() >= Build.VERSION_CODES.FROYO) {
+                pname = sa.getNonConfigurationString(R.styleable.AndroidManifestService_process,
+                        Configuration.NATIVE_CONFIG_VERSION);
+            } else {
+                // Some older apps have been seen to use a resource reference
+                // here that on older builds was ignored (with a warning).  We
+                // need to continue to do this for them so they don't break.
+                pname = sa.getNonResourceString(R.styleable.AndroidManifestService_process);
+            }
+
+            result.setProcessName(packageProcessName, PackageParser.buildProcessName(packageName,
+                    packageProcessName, pname,
+                    flags, separateProcesses, outError));
+
+            result.descriptionRes = sa.getResourceId(
+                    R.styleable.AndroidManifestService_description, 0);
+
+            result.enabled = sa.getBoolean(R.styleable.AndroidManifestService_enabled, true);
+
+            setExported = sa.hasValue(
+                    R.styleable.AndroidManifestService_exported);
+            if (setExported) {
+                result.exported = sa.getBoolean(
+                        R.styleable.AndroidManifestService_exported, false);
+            }
+
+            String str = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestService_permission, 0);
+            if (str == null) {
+                result.setPermission(parsingPackage.getPermission());
+            } else {
+                result.setPermission(str);
+            }
+
+            result.setSplitName(
+                    sa.getNonConfigurationString(R.styleable.AndroidManifestService_splitName, 0));
+
+            result.foregroundServiceType = sa.getInt(
+                    R.styleable.AndroidManifestService_foregroundServiceType,
+                    ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE);
+
+            result.flags = 0;
+            if (sa.getBoolean(
+                    R.styleable.AndroidManifestService_stopWithTask,
+                    false)) {
+                result.flags |= ServiceInfo.FLAG_STOP_WITH_TASK;
+            }
+            if (sa.getBoolean(
+                    R.styleable.AndroidManifestService_isolatedProcess,
+                    false)) {
+                result.flags |= ServiceInfo.FLAG_ISOLATED_PROCESS;
+            }
+            if (sa.getBoolean(
+                    R.styleable.AndroidManifestService_externalService,
+                    false)) {
+                result.flags |= ServiceInfo.FLAG_EXTERNAL_SERVICE;
+            }
+            if (sa.getBoolean(
+                    R.styleable.AndroidManifestService_useAppZygote,
+                    false)) {
+                result.flags |= ServiceInfo.FLAG_USE_APP_ZYGOTE;
+            }
+            if (sa.getBoolean(
+                    R.styleable.AndroidManifestService_singleUser,
+                    false)) {
+                result.flags |= ServiceInfo.FLAG_SINGLE_USER;
+            }
+
+            result.directBootAware = sa.getBoolean(
+                    R.styleable.AndroidManifestService_directBootAware,
+                    false);
+            if (result.directBootAware) {
+                parsingPackage.setPartiallyDirectBootAware(true);
+            }
+
+            visibleToEphemeral = sa.getBoolean(
+                    R.styleable.AndroidManifestService_visibleToInstantApps, false);
+            if (visibleToEphemeral) {
+                result.flags |= ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP;
+                parsingPackage.setVisibleToInstantApps(true);
+            }
+        } finally {
+            if (sa != null) {
+                sa.recycle();
+            }
+        }
+
+        if (parsingPackage.cantSaveState()) {
+            // A heavy-weight application can not have services in its main process
+            // We can do direct compare because we intern all strings.
+            if (Objects.equals(result.getProcessName(), parsingPackage.getPackageName())) {
+                outError[0] = "Heavy-weight applications can not have services in main process";
+                return null;
+            }
+        }
+
+        int outerDepth = parser.getDepth();
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG
+                || parser.getDepth() > outerDepth)) {
+            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                continue;
+            }
+
+            if (parser.getName().equals("intent-filter")) {
+                ParsedServiceIntentInfo intent = new ParsedServiceIntentInfo(packageName,
+                        result.className);
+                if (!parseIntentInfo(intent, parsingPackage, res, parser, true /*allowGlobs*/,
+                        false /*allowAutoVerify*/,
+                        outError)) {
+                    return null;
+                }
+                if (visibleToEphemeral) {
+                    intent.setVisibilityToInstantApp(IntentFilter.VISIBILITY_EXPLICIT);
+                    result.flags |= ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP;
+                }
+                result.order = Math.max(intent.getOrder(), result.order);
+                result.intents.add(intent);
+            } else if (parser.getName().equals("meta-data")) {
+                if ((result.metaData = ApkParseUtils.parseMetaData(parsingPackage, res, parser,
+                        result.metaData,
+                        outError)) == null) {
+                    return null;
+                }
+            } else {
+                if (!PackageParser.RIGID_PARSER) {
+                    Slog.w(TAG, "Unknown element under <service>: "
+                            + parser.getName() + " at " + parsingPackage.getBaseCodePath() + " "
+                            + parser.getPositionDescription());
+                    XmlUtils.skipCurrentTag(parser);
+                    continue;
+                } else {
+                    outError[0] = "Bad element under <service>: " + parser.getName();
+                    return null;
+                }
+            }
+        }
+
+        if (!setExported) {
+            result.exported = result.intents.size() > 0;
+        }
+
+        return result;
+    }
+
+    public static ParsedProvider parseProvider(
+            String[] separateProcesses,
+            ParsingPackage parsingPackage,
+            Resources res,
+            XmlResourceParser parser, int flags, String[] outError)
+            throws XmlPullParserException, IOException {
+        TypedArray sa = null;
+        String cpname;
+        boolean visibleToEphemeral;
+
+        int targetSdkVersion = parsingPackage.getTargetSdkVersion();
+        String packageName = parsingPackage.getPackageName();
+        String packageProcessName = parsingPackage.getProcessName();
+        ParsedProvider result = new ParsedProvider();
+
+        try {
+            sa = res.obtainAttributes(parser,
+                    R.styleable.AndroidManifestProvider);
+
+            String name = sa.getNonConfigurationString(R.styleable.AndroidManifestProvider_name, 0);
+            if (name == null) {
+                outError[0] = "<provider> does not specify android:name";
+                return null;
+            } else {
+                String className = ApkParseUtils.buildClassName(packageName, name);
+                if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) {
+                    outError[0] = "<provider> invalid android:name";
+                    return null;
+                } else if (className == null) {
+                    outError[0] = "Empty class name in package " + packageName;
+                    return null;
+                }
+
+                result.className = className;
+            }
+
+            int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId(
+                    R.styleable.AndroidManifestProvider_roundIcon, 0) : 0;
+            if (roundIconVal != 0) {
+                result.icon = roundIconVal;
+                result.nonLocalizedLabel = null;
+            } else {
+                int iconVal = sa.getResourceId(R.styleable.AndroidManifestProvider_icon, 0);
+                if (iconVal != 0) {
+                    result.icon = iconVal;
+                    result.nonLocalizedLabel = null;
+                }
+            }
+
+            int logoVal = sa.getResourceId(R.styleable.AndroidManifestProvider_logo, 0);
+            if (logoVal != 0) {
+                result.logo = logoVal;
+            }
+
+            int bannerVal = sa.getResourceId(R.styleable.AndroidManifestProvider_banner, 0);
+            if (bannerVal != 0) {
+                result.banner = bannerVal;
+            }
+
+            TypedValue v = sa.peekValue(R.styleable.AndroidManifestProvider_label);
+            if (v != null && (result.labelRes = v.resourceId) == 0) {
+                result.nonLocalizedLabel = v.coerceToString();
+            }
+
+            result.setPackageNameInternal(packageName);
+
+            CharSequence pname;
+            if (parsingPackage.getTargetSdkVersion() >= Build.VERSION_CODES.FROYO) {
+                pname = sa.getNonConfigurationString(R.styleable.AndroidManifestProvider_process,
+                        Configuration.NATIVE_CONFIG_VERSION);
+            } else {
+                // Some older apps have been seen to use a resource reference
+                // here that on older builds was ignored (with a warning).  We
+                // need to continue to do this for them so they don't break.
+                pname = sa.getNonResourceString(R.styleable.AndroidManifestProvider_process);
+            }
+
+            result.setProcessName(packageProcessName, PackageParser.buildProcessName(packageName,
+                    packageProcessName, pname,
+                    flags, separateProcesses, outError));
+
+            result.descriptionRes = sa.getResourceId(
+                    R.styleable.AndroidManifestProvider_description, 0);
+
+            result.enabled = sa.getBoolean(R.styleable.AndroidManifestProvider_enabled, true);
+
+            boolean providerExportedDefault = false;
+
+            if (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR1) {
+                // For compatibility, applications targeting API level 16 or lower
+                // should have their content providers exported by default, unless they
+                // specify otherwise.
+                providerExportedDefault = true;
+            }
+
+            result.exported = sa.getBoolean(
+                    R.styleable.AndroidManifestProvider_exported,
+                    providerExportedDefault);
+
+            cpname = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestProvider_authorities, 0);
+
+            result.isSyncable = sa.getBoolean(
+                    R.styleable.AndroidManifestProvider_syncable,
+                    false);
+
+            String permission = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestProvider_permission, 0);
+            String str = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestProvider_readPermission, 0);
+            if (str == null) {
+                str = permission;
+            }
+            if (str == null) {
+                result.setReadPermission(parsingPackage.getPermission());
+            } else {
+                result.setReadPermission(str);
+            }
+            str = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestProvider_writePermission, 0);
+            if (str == null) {
+                str = permission;
+            }
+            if (str == null) {
+                result.setWritePermission(parsingPackage.getPermission());
+            } else {
+                result.setWritePermission(str);
+            }
+
+            result.grantUriPermissions = sa.getBoolean(
+                    R.styleable.AndroidManifestProvider_grantUriPermissions,
+                    false);
+
+            result.forceUriPermissions = sa.getBoolean(
+                    R.styleable.AndroidManifestProvider_forceUriPermissions,
+                    false);
+
+            result.multiProcess = sa.getBoolean(
+                    R.styleable.AndroidManifestProvider_multiprocess,
+                    false);
+
+            result.initOrder = sa.getInt(
+                    R.styleable.AndroidManifestProvider_initOrder,
+                    0);
+
+            result.setSplitName(
+                    sa.getNonConfigurationString(R.styleable.AndroidManifestProvider_splitName, 0));
+
+            result.flags = 0;
+
+            if (sa.getBoolean(
+                    R.styleable.AndroidManifestProvider_singleUser,
+                    false)) {
+                result.flags |= ProviderInfo.FLAG_SINGLE_USER;
+            }
+
+            result.directBootAware = sa.getBoolean(
+                    R.styleable.AndroidManifestProvider_directBootAware,
+                    false);
+            if (result.directBootAware) {
+                parsingPackage.setPartiallyDirectBootAware(true);
+            }
+
+            visibleToEphemeral =
+                    sa.getBoolean(R.styleable.AndroidManifestProvider_visibleToInstantApps, false);
+            if (visibleToEphemeral) {
+                result.flags |= ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP;
+                parsingPackage.setVisibleToInstantApps(true);
+            }
+        } finally {
+            if (sa != null) {
+                sa.recycle();
+            }
+        }
+
+        if ((parsingPackage.getPrivateFlags() & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE)
+                != 0) {
+            // A heavy-weight application can not have providers in its main process
+            if (result.getProcessName().equals(packageName)) {
+                outError[0] = "Heavy-weight applications can not have providers in main process";
+                return null;
+            }
+        }
+
+        if (cpname == null) {
+            outError[0] = "<provider> does not include authorities attribute";
+            return null;
+        }
+        if (cpname.length() <= 0) {
+            outError[0] = "<provider> has empty authorities attribute";
+            return null;
+        }
+        result.setAuthority(cpname);
+
+        if (!parseProviderTags(parsingPackage, res, parser, visibleToEphemeral, result, outError)) {
+            return null;
+        }
+
+        return result;
+    }
+
+    public static ParsedQueriesIntentInfo parsedParsedQueriesIntentInfo(
+            ParsingPackage parsingPackage,
+            Resources res,
+            XmlResourceParser parser,
+            String[] outError
+    ) throws IOException, XmlPullParserException {
+        ParsedQueriesIntentInfo intentInfo = new ParsedQueriesIntentInfo(
+                parsingPackage.getPackageName(),
+                null
+        );
+        if (!parseIntentInfo(
+                intentInfo,
+                parsingPackage,
+                res,
+                parser,
+                true /*allowGlobs*/,
+                true /*allowAutoVerify*/,
+                outError
+        )) {
+            return null;
+        }
+        return intentInfo;
+    }
+
+    private static boolean parseProviderTags(
+            ParsingPackage parsingPackage,
+            Resources res, XmlResourceParser parser,
+            boolean visibleToEphemeral, ParsedProvider outInfo, String[] outError)
+            throws XmlPullParserException, IOException {
+        int outerDepth = parser.getDepth();
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG
+                || parser.getDepth() > outerDepth)) {
+            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                continue;
+            }
+
+            if (parser.getName().equals("intent-filter")) {
+                ParsedProviderIntentInfo intent = new ParsedProviderIntentInfo(
+                        parsingPackage.getPackageName(), outInfo.className);
+                if (!parseIntentInfo(intent, parsingPackage, res, parser, true /*allowGlobs*/,
+                        false /*allowAutoVerify*/,
+                        outError)) {
+                    return false;
+                }
+                if (visibleToEphemeral) {
+                    intent.setVisibilityToInstantApp(IntentFilter.VISIBILITY_EXPLICIT);
+                    outInfo.flags |= ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP;
+                }
+                outInfo.order = Math.max(intent.getOrder(), outInfo.order);
+                outInfo.intents.add(intent);
+
+            } else if (parser.getName().equals("meta-data")) {
+                Bundle metaData = ApkParseUtils.parseMetaData(parsingPackage, res, parser,
+                        outInfo.metaData, outError);
+                if (metaData == null) {
+                    return false;
+                } else {
+                    outInfo.metaData = metaData;
+                }
+
+            } else if (parser.getName().equals("grant-uri-permission")) {
+                TypedArray sa = res.obtainAttributes(parser,
+                        R.styleable.AndroidManifestGrantUriPermission);
+
+                PatternMatcher pa = null;
+
+                String str = sa.getNonConfigurationString(
+                        R.styleable.AndroidManifestGrantUriPermission_path, 0);
+                if (str != null) {
+                    pa = new PatternMatcher(str, PatternMatcher.PATTERN_LITERAL);
+                }
+
+                str = sa.getNonConfigurationString(
+                        R.styleable.AndroidManifestGrantUriPermission_pathPrefix, 0);
+                if (str != null) {
+                    pa = new PatternMatcher(str, PatternMatcher.PATTERN_PREFIX);
+                }
+
+                str = sa.getNonConfigurationString(
+                        R.styleable.AndroidManifestGrantUriPermission_pathPattern, 0);
+                if (str != null) {
+                    pa = new PatternMatcher(str, PatternMatcher.PATTERN_SIMPLE_GLOB);
+                }
+
+                sa.recycle();
+
+                if (pa != null) {
+                    if (outInfo.uriPermissionPatterns == null) {
+                        outInfo.uriPermissionPatterns = new PatternMatcher[1];
+                        outInfo.uriPermissionPatterns[0] = pa;
+                    } else {
+                        final int N = outInfo.uriPermissionPatterns.length;
+                        PatternMatcher[] newp = new PatternMatcher[N + 1];
+                        System.arraycopy(outInfo.uriPermissionPatterns, 0, newp, 0, N);
+                        newp[N] = pa;
+                        outInfo.uriPermissionPatterns = newp;
+                    }
+                    outInfo.grantUriPermissions = true;
+                } else {
+                    if (!PackageParser.RIGID_PARSER) {
+                        Slog.w(TAG, "Unknown element under <path-permission>: "
+                                + parser.getName() + " at " + parsingPackage.getBaseCodePath()
+                                + " "
+                                + parser.getPositionDescription());
+                        XmlUtils.skipCurrentTag(parser);
+                        continue;
+                    } else {
+                        outError[0] = "No path, pathPrefix, or pathPattern for <path-permission>";
+                        return false;
+                    }
+                }
+                XmlUtils.skipCurrentTag(parser);
+
+            } else if (parser.getName().equals("path-permission")) {
+                TypedArray sa = res.obtainAttributes(parser,
+                        R.styleable.AndroidManifestPathPermission);
+
+                PathPermission pa = null;
+
+                String permission = sa.getNonConfigurationString(
+                        R.styleable.AndroidManifestPathPermission_permission, 0);
+                String readPermission = sa.getNonConfigurationString(
+                        R.styleable.AndroidManifestPathPermission_readPermission, 0);
+                if (readPermission == null) {
+                    readPermission = permission;
+                }
+                String writePermission = sa.getNonConfigurationString(
+                        R.styleable.AndroidManifestPathPermission_writePermission, 0);
+                if (writePermission == null) {
+                    writePermission = permission;
+                }
+
+                boolean havePerm = false;
+                if (readPermission != null) {
+                    readPermission = readPermission.intern();
+                    havePerm = true;
+                }
+                if (writePermission != null) {
+                    writePermission = writePermission.intern();
+                    havePerm = true;
+                }
+
+                if (!havePerm) {
+                    if (!PackageParser.RIGID_PARSER) {
+                        Slog.w(TAG, "No readPermission or writePermssion for <path-permission>: "
+                                + parser.getName() + " at " + parsingPackage.getBaseCodePath()
+                                + " "
+                                + parser.getPositionDescription());
+                        XmlUtils.skipCurrentTag(parser);
+                        continue;
+                    } else {
+                        outError[0] = "No readPermission or writePermssion for <path-permission>";
+                        return false;
+                    }
+                }
+
+                String path = sa.getNonConfigurationString(
+                        R.styleable.AndroidManifestPathPermission_path, 0);
+                if (path != null) {
+                    pa = new PathPermission(path,
+                            PatternMatcher.PATTERN_LITERAL, readPermission, writePermission);
+                }
+
+                path = sa.getNonConfigurationString(
+                        R.styleable.AndroidManifestPathPermission_pathPrefix, 0);
+                if (path != null) {
+                    pa = new PathPermission(path,
+                            PatternMatcher.PATTERN_PREFIX, readPermission, writePermission);
+                }
+
+                path = sa.getNonConfigurationString(
+                        R.styleable.AndroidManifestPathPermission_pathPattern, 0);
+                if (path != null) {
+                    pa = new PathPermission(path,
+                            PatternMatcher.PATTERN_SIMPLE_GLOB, readPermission, writePermission);
+                }
+
+                path = sa.getNonConfigurationString(
+                        R.styleable.AndroidManifestPathPermission_pathAdvancedPattern, 0);
+                if (path != null) {
+                    pa = new PathPermission(path,
+                            PatternMatcher.PATTERN_ADVANCED_GLOB, readPermission, writePermission);
+                }
+
+                sa.recycle();
+
+                if (pa != null) {
+                    if (outInfo.pathPermissions == null) {
+                        outInfo.pathPermissions = new PathPermission[1];
+                        outInfo.pathPermissions[0] = pa;
+                    } else {
+                        final int N = outInfo.pathPermissions.length;
+                        PathPermission[] newp = new PathPermission[N + 1];
+                        System.arraycopy(outInfo.pathPermissions, 0, newp, 0, N);
+                        newp[N] = pa;
+                        outInfo.pathPermissions = newp;
+                    }
+                } else {
+                    if (!PackageParser.RIGID_PARSER) {
+                        Slog.w(TAG, "No path, pathPrefix, or pathPattern for <path-permission>: "
+                                + parser.getName() + " at " + parsingPackage.getBaseCodePath()
+                                + " "
+                                + parser.getPositionDescription());
+                        XmlUtils.skipCurrentTag(parser);
+                        continue;
+                    }
+                    outError[0] = "No path, pathPrefix, or pathPattern for <path-permission>";
+                    return false;
+                }
+                XmlUtils.skipCurrentTag(parser);
+
+            } else {
+                if (!PackageParser.RIGID_PARSER) {
+                    Slog.w(TAG, "Unknown element under <provider>: "
+                            + parser.getName() + " at " + parsingPackage.getBaseCodePath() + " "
+                            + parser.getPositionDescription());
+                    XmlUtils.skipCurrentTag(parser);
+                    continue;
+                } else {
+                    outError[0] = "Bad element under <provider>: " + parser.getName();
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    public static ParsedActivity parseActivityAlias(
+            ParsingPackage parsingPackage,
+            Resources res,
+            XmlResourceParser parser,
+            String[] outError)
+            throws XmlPullParserException, IOException {
+        TypedArray sa = res.obtainAttributes(parser,
+                R.styleable.AndroidManifestActivityAlias);
+
+        String targetActivity = sa.getNonConfigurationString(
+                R.styleable.AndroidManifestActivityAlias_targetActivity,
+                Configuration.NATIVE_CONFIG_VERSION);
+        if (targetActivity == null) {
+            outError[0] = "<activity-alias> does not specify android:targetActivity";
+            sa.recycle();
+            return null;
+        }
+
+        String packageName = parsingPackage.getPackageName();
+        targetActivity = ApkParseUtils.buildClassName(packageName, targetActivity);
+        if (targetActivity == null) {
+            outError[0] = "Empty class name in package " + packageName;
+            sa.recycle();
+            return null;
+        }
+
+        ParsedActivity target = null;
+
+        List<ParsedActivity> activities = parsingPackage.getActivities();
+        final int NA = activities.size();
+        for (int i = 0; i < NA; i++) {
+            ParsedActivity t = activities.get(i);
+            if (targetActivity.equals(t.className)) {
+                target = t;
+                break;
+            }
+        }
+
+        if (target == null) {
+            outError[0] = "<activity-alias> target activity " + targetActivity
+                    + " not found in manifest with activities = " + parsingPackage.getActivities()
+                    + ", parsedActivities = " + activities;
+            sa.recycle();
+            return null;
+        }
+
+        ParsedActivity result = new ParsedActivity();
+        result.setPackageNameInternal(target.getPackageName());
+        result.targetActivity = targetActivity;
+        result.configChanges = target.configChanges;
+        result.flags = target.flags;
+        result.privateFlags = target.privateFlags;
+        result.icon = target.icon;
+        result.logo = target.logo;
+        result.banner = target.banner;
+        result.labelRes = target.labelRes;
+        result.nonLocalizedLabel = target.nonLocalizedLabel;
+        result.launchMode = target.launchMode;
+        result.lockTaskLaunchMode = target.lockTaskLaunchMode;
+        result.descriptionRes = target.descriptionRes;
+        result.screenOrientation = target.screenOrientation;
+        result.taskAffinity = target.taskAffinity;
+        result.theme = target.theme;
+        result.softInputMode = target.softInputMode;
+        result.uiOptions = target.uiOptions;
+        result.parentActivityName = target.parentActivityName;
+        result.maxRecents = target.maxRecents;
+        result.windowLayout = target.windowLayout;
+        result.resizeMode = target.resizeMode;
+        result.maxAspectRatio = target.maxAspectRatio;
+        result.hasMaxAspectRatio = target.hasMaxAspectRatio;
+        result.minAspectRatio = target.minAspectRatio;
+        result.hasMinAspectRatio = target.hasMinAspectRatio;
+        result.requestedVrComponent = target.requestedVrComponent;
+        result.directBootAware = target.directBootAware;
+
+        result.setProcessName(parsingPackage.getAppInfoProcessName(), target.getProcessName());
+
+        // Not all attributes from the target ParsedActivity are copied to the alias.
+        // Careful when adding an attribute and determine whether or not it should be copied.
+//        result.enabled = target.enabled;
+//        result.exported = target.exported;
+//        result.permission = target.permission;
+//        result.splitName = target.splitName;
+//        result.documentLaunchMode = target.documentLaunchMode;
+//        result.persistableMode = target.persistableMode;
+//        result.rotationAnimation = target.rotationAnimation;
+//        result.colorMode = target.colorMode;
+//        result.intents.addAll(target.intents);
+//        result.order = target.order;
+//        result.metaData = target.metaData;
+
+        String name = sa.getNonConfigurationString(R.styleable.AndroidManifestActivityAlias_name,
+                0);
+        if (name == null) {
+            outError[0] = "<activity-alias> does not specify android:name";
+            return null;
+        } else {
+            String className = ApkParseUtils.buildClassName(packageName, name);
+            if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) {
+                outError[0] = "<activity-alias> invalid android:name";
+                return null;
+            } else if (className == null) {
+                outError[0] = "Empty class name in package " + packageName;
+                return null;
+            }
+
+            result.className = className;
+        }
+
+        int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId(
+                R.styleable.AndroidManifestActivityAlias_roundIcon, 0) : 0;
+        if (roundIconVal != 0) {
+            result.icon = roundIconVal;
+            result.nonLocalizedLabel = null;
+        } else {
+            int iconVal = sa.getResourceId(R.styleable.AndroidManifestActivityAlias_icon, 0);
+            if (iconVal != 0) {
+                result.icon = iconVal;
+                result.nonLocalizedLabel = null;
+            }
+        }
+
+        int logoVal = sa.getResourceId(R.styleable.AndroidManifestActivityAlias_logo, 0);
+        if (logoVal != 0) {
+            result.logo = logoVal;
+        }
+
+        int bannerVal = sa.getResourceId(R.styleable.AndroidManifestActivityAlias_banner, 0);
+        if (bannerVal != 0) {
+            result.banner = bannerVal;
+        }
+
+        TypedValue v = sa.peekValue(R.styleable.AndroidManifestActivityAlias_label);
+        if (v != null && (result.labelRes = v.resourceId) == 0) {
+            result.nonLocalizedLabel = v.coerceToString();
+        }
+
+        result.setPackageNameInternal(packageName);
+
+        result.descriptionRes = sa.getResourceId(
+                R.styleable.AndroidManifestActivityAlias_description, 0);
+
+        result.enabled = sa.getBoolean(R.styleable.AndroidManifestActivityAlias_enabled, true);
+
+        final boolean setExported = sa.hasValue(
+                R.styleable.AndroidManifestActivityAlias_exported);
+        if (setExported) {
+            result.exported = sa.getBoolean(
+                    R.styleable.AndroidManifestActivityAlias_exported, false);
+        }
+
+        String str;
+        str = sa.getNonConfigurationString(
+                R.styleable.AndroidManifestActivityAlias_permission, 0);
+        if (str != null) {
+            result.setPermission(str);
+        }
+
+        String parentName = sa.getNonConfigurationString(
+                R.styleable.AndroidManifestActivityAlias_parentActivityName,
+                Configuration.NATIVE_CONFIG_VERSION);
+        if (parentName != null) {
+            String parentClassName = ApkParseUtils.buildClassName(result.getPackageName(),
+                    parentName);
+            if (parentClassName == null) {
+                Log.e(TAG, "Activity alias " + result.className +
+                        " specified invalid parentActivityName " + parentName);
+                outError[0] = null;
+            } else {
+                result.parentActivityName = parentClassName;
+            }
+        }
+
+        // TODO add visibleToInstantApps attribute to activity alias
+        final boolean visibleToEphemeral =
+                ((result.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0);
+
+        sa.recycle();
+
+        if (outError[0] != null) {
+            return null;
+        }
+
+        int outerDepth = parser.getDepth();
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG
+                || parser.getDepth() > outerDepth)) {
+            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                continue;
+            }
+
+            String tagName = parser.getName();
+            if (tagName.equals("intent-filter")) {
+                ParsedActivityIntentInfo intent = new ParsedActivityIntentInfo(packageName,
+                        result.className);
+                if (!parseIntentInfo(intent, parsingPackage, res, parser, true /*allowGlobs*/,
+                        true /*allowAutoVerify*/, outError)) {
+                    return null;
+                }
+                if (intent.countActions() == 0) {
+                    Slog.w(TAG, "No actions in intent filter at "
+                            + parsingPackage.getBaseCodePath() + " "
+                            + parser.getPositionDescription());
+                } else {
+                    result.order = Math.max(intent.getOrder(), result.order);
+                    result.addIntent(intent);
+                }
+                // adjust activity flags when we implicitly expose it via a browsable filter
+                final int visibility = visibleToEphemeral
+                        ? IntentFilter.VISIBILITY_EXPLICIT
+                        : isImplicitlyExposedIntent(intent)
+                                ? IntentFilter.VISIBILITY_IMPLICIT
+                                : IntentFilter.VISIBILITY_NONE;
+                intent.setVisibilityToInstantApp(visibility);
+                if (intent.isVisibleToInstantApp()) {
+                    result.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP;
+                }
+                if (intent.isImplicitlyVisibleToInstantApp()) {
+                    result.flags |= ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP;
+                }
+            } else if (tagName.equals("meta-data")) {
+                if ((result.metaData = ApkParseUtils.parseMetaData(parsingPackage, res, parser,
+                        result.metaData,
+                        outError)) == null) {
+                    return null;
+                }
+            } else {
+                if (!PackageParser.RIGID_PARSER) {
+                    Slog.w(TAG, "Unknown element under <activity-alias>: " + tagName
+                            + " at " + parsingPackage.getBaseCodePath() + " "
+                            + parser.getPositionDescription());
+                    XmlUtils.skipCurrentTag(parser);
+                    continue;
+                } else {
+                    outError[0] = "Bad element under <activity-alias>: " + tagName;
+                    return null;
+                }
+            }
+        }
+
+        if (!setExported) {
+            result.exported = result.intents.size() > 0;
+        }
+
+        return result;
+    }
+
+    public static ParsedPermission parsePermission(
+            ParsingPackage parsingPackage,
+            Resources res,
+            XmlResourceParser parser,
+            String[] outError
+    ) throws IOException, XmlPullParserException {
+        TypedArray sa = null;
+        String packageName = parsingPackage.getPackageName();
+        ParsedPermission result = new ParsedPermission();
+
+        try {
+            sa = res.obtainAttributes(parser, R.styleable.AndroidManifestPermission);
+
+            String name = sa.getNonConfigurationString(R.styleable.AndroidManifestPermission_name,
+                    0);
+            if (name == null) {
+                outError[0] = "<permission> does not specify android:name";
+                return null;
+            } else {
+                String className = ApkParseUtils.buildClassName(packageName, name);
+                if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) {
+                    outError[0] = "<permission> invalid android:name";
+                    return null;
+                } else if (className == null) {
+                    outError[0] = "Empty class name in package " + packageName;
+                    return null;
+                }
+
+                result.className = className;
+            }
+
+            int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId(
+                    R.styleable.AndroidManifestPermission_roundIcon, 0) : 0;
+            if (roundIconVal != 0) {
+                result.icon = roundIconVal;
+                result.nonLocalizedLabel = null;
+            } else {
+                int iconVal = sa.getResourceId(R.styleable.AndroidManifestPermission_icon, 0);
+                if (iconVal != 0) {
+                    result.icon = iconVal;
+                    result.nonLocalizedLabel = null;
+                }
+            }
+
+            int logoVal = sa.getResourceId(R.styleable.AndroidManifestPermission_logo, 0);
+            if (logoVal != 0) {
+                result.logo = logoVal;
+            }
+
+            int bannerVal = sa.getResourceId(R.styleable.AndroidManifestPermission_banner, 0);
+            if (bannerVal != 0) {
+                result.banner = bannerVal;
+            }
+
+            TypedValue v = sa.peekValue(R.styleable.AndroidManifestPermission_label);
+            if (v != null && (result.labelRes = v.resourceId) == 0) {
+                result.nonLocalizedLabel = v.coerceToString();
+            }
+
+            result.setPackageNameInternal(packageName);
+
+            result.descriptionRes = sa.getResourceId(
+                    R.styleable.AndroidManifestPermission_description, 0);
+
+            if (sa.hasValue(
+                    R.styleable.AndroidManifestPermission_backgroundPermission)) {
+                if ("android".equals(packageName)) {
+                    result.backgroundPermission = sa.getNonResourceString(
+                            R.styleable
+                                    .AndroidManifestPermission_backgroundPermission);
+                } else {
+                    Slog.w(TAG, packageName + " defines a background permission. Only the "
+                            + "'android' package can do that.");
+                }
+            }
+
+            // Note: don't allow this value to be a reference to a resource
+            // that may change.
+            result.setGroup(sa.getNonResourceString(
+                    R.styleable.AndroidManifestPermission_permissionGroup));
+
+            result.requestRes = sa.getResourceId(
+                    R.styleable.AndroidManifestPermission_request, 0);
+
+            result.protectionLevel = sa.getInt(
+                    R.styleable.AndroidManifestPermission_protectionLevel,
+                    PermissionInfo.PROTECTION_NORMAL);
+
+            result.flags = sa.getInt(
+                    R.styleable.AndroidManifestPermission_permissionFlags, 0);
+
+            // For now only platform runtime permissions can be restricted
+            if (!result.isRuntime() || !"android".equals(result.getPackageName())) {
+                result.flags &= ~PermissionInfo.FLAG_HARD_RESTRICTED;
+                result.flags &= ~PermissionInfo.FLAG_SOFT_RESTRICTED;
+            } else {
+                // The platform does not get to specify conflicting permissions
+                if ((result.flags & PermissionInfo.FLAG_HARD_RESTRICTED) != 0
+                        && (result.flags & PermissionInfo.FLAG_SOFT_RESTRICTED) != 0) {
+                    throw new IllegalStateException("Permission cannot be both soft and hard"
+                            + " restricted: " + result.getName());
+                }
+            }
+
+        } finally {
+            if (sa != null) {
+                sa.recycle();
+            }
+        }
+
+        if (result.protectionLevel == -1) {
+            outError[0] = "<permission> does not specify protectionLevel";
+            return null;
+        }
+
+        result.protectionLevel = PermissionInfo.fixProtectionLevel(result.protectionLevel);
+
+        if (result.getProtectionFlags() != 0) {
+            if ((result.protectionLevel & PermissionInfo.PROTECTION_FLAG_INSTANT) == 0
+                    && (result.protectionLevel & PermissionInfo.PROTECTION_FLAG_RUNTIME_ONLY)
+                    == 0
+                    && (result.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE) !=
+                    PermissionInfo.PROTECTION_SIGNATURE) {
+                outError[0] = "<permission>  protectionLevel specifies a non-instant flag but is "
+                        + "not based on signature type";
+                return null;
+            }
+        }
+
+        boolean success = parseAllMetaData(parsingPackage, res, parser,
+                "<permission>", result, outError);
+        if (!success || outError[0] != null) {
+            return null;
+        }
+
+        return result;
+    }
+
+    public static ParsedPermission parsePermissionTree(
+            ParsingPackage parsingPackage,
+            Resources res,
+            XmlResourceParser parser,
+            String[] outError
+    ) throws IOException, XmlPullParserException {
+        TypedArray sa = null;
+        String packageName = parsingPackage.getPackageName();
+        ParsedPermission result = new ParsedPermission();
+
+        try {
+            sa = res.obtainAttributes(parser, R.styleable.AndroidManifestPermissionTree);
+
+            String name = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestPermissionTree_name, 0);
+            if (name == null) {
+                outError[0] = "<permission-tree> does not specify android:name";
+                return null;
+            } else {
+                String className = ApkParseUtils.buildClassName(packageName, name);
+                if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) {
+                    outError[0] = "<permission-tree> invalid android:name";
+                    return null;
+                } else if (className == null) {
+                    outError[0] = "Empty class name in package " + packageName;
+                    return null;
+                }
+
+                result.className = className;
+            }
+
+            int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId(
+                    R.styleable.AndroidManifestPermissionTree_roundIcon, 0) : 0;
+            if (roundIconVal != 0) {
+                result.icon = roundIconVal;
+                result.nonLocalizedLabel = null;
+            } else {
+                int iconVal = sa.getResourceId(R.styleable.AndroidManifestPermissionTree_icon, 0);
+                if (iconVal != 0) {
+                    result.icon = iconVal;
+                    result.nonLocalizedLabel = null;
+                }
+            }
+
+            int logoVal = sa.getResourceId(R.styleable.AndroidManifestPermissionTree_logo, 0);
+            if (logoVal != 0) {
+                result.logo = logoVal;
+            }
+
+            int bannerVal = sa.getResourceId(R.styleable.AndroidManifestPermissionTree_banner, 0);
+            if (bannerVal != 0) {
+                result.banner = bannerVal;
+            }
+
+            TypedValue v = sa.peekValue(R.styleable.AndroidManifestPermissionTree_label);
+            if (v != null && (result.labelRes = v.resourceId) == 0) {
+                result.nonLocalizedLabel = v.coerceToString();
+            }
+
+            result.setPackageNameInternal(packageName);
+        } finally {
+            if (sa != null) {
+                sa.recycle();
+            }
+        }
+
+        int index = result.getName().indexOf('.');
+        if (index > 0) {
+            index = result.getName().indexOf('.', index + 1);
+        }
+        if (index < 0) {
+            outError[0] =
+                    "<permission-tree> name has less than three segments: " + result.getName();
+            return null;
+        }
+
+        result.descriptionRes = 0;
+        result.requestRes = 0;
+        result.protectionLevel = PermissionInfo.PROTECTION_NORMAL;
+        result.tree = true;
+
+        boolean success = parseAllMetaData(parsingPackage, res, parser,
+                "<permission-tree>", result, outError);
+        if (!success || outError[0] != null) {
+            return null;
+        }
+
+        return result;
+    }
+
+    public static ParsedPermissionGroup parsePermissionGroup(
+            ParsingPackage parsingPackage,
+            Resources res,
+            XmlResourceParser parser,
+            String[] outError
+    ) throws IOException, XmlPullParserException {
+        TypedArray sa = null;
+        String packageName = parsingPackage.getPackageName();
+        ParsedPermissionGroup result = new ParsedPermissionGroup();
+
+        try {
+            sa = res.obtainAttributes(parser, R.styleable.AndroidManifestPermissionGroup);
+
+            String name = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestPermissionGroup_name, 0);
+            if (name == null) {
+                outError[0] = "<permission> does not specify android:name";
+                return null;
+            } else {
+                String className = ApkParseUtils.buildClassName(packageName, name);
+                if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) {
+                    outError[0] = "<permission> invalid android:name";
+                    return null;
+                } else if (className == null) {
+                    outError[0] = "Empty class name in package " + packageName;
+                    return null;
+                }
+
+                result.className = className;
+            }
+
+            int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId(
+                    R.styleable.AndroidManifestPermissionGroup_roundIcon, 0) : 0;
+            if (roundIconVal != 0) {
+                result.icon = roundIconVal;
+                result.nonLocalizedLabel = null;
+            } else {
+                int iconVal = sa.getResourceId(R.styleable.AndroidManifestPermissionGroup_icon, 0);
+                if (iconVal != 0) {
+                    result.icon = iconVal;
+                    result.nonLocalizedLabel = null;
+                }
+            }
+
+            int logoVal = sa.getResourceId(R.styleable.AndroidManifestPermissionGroup_logo, 0);
+            if (logoVal != 0) {
+                result.logo = logoVal;
+            }
+
+            int bannerVal = sa.getResourceId(R.styleable.AndroidManifestPermissionGroup_banner, 0);
+            if (bannerVal != 0) {
+                result.banner = bannerVal;
+            }
+
+            TypedValue v = sa.peekValue(R.styleable.AndroidManifestPermissionGroup_label);
+            if (v != null && (result.labelRes = v.resourceId) == 0) {
+                result.nonLocalizedLabel = v.coerceToString();
+            }
+
+            result.setPackageNameInternal(packageName);
+
+            result.descriptionRes = sa.getResourceId(
+                    R.styleable.AndroidManifestPermissionGroup_description, 0);
+
+            result.requestDetailResourceId = sa.getResourceId(
+                    R.styleable.AndroidManifestPermissionGroup_requestDetail, 0);
+            result.backgroundRequestResourceId = sa.getResourceId(
+                    R.styleable.AndroidManifestPermissionGroup_backgroundRequest,
+                    0);
+            result.backgroundRequestDetailResourceId = sa.getResourceId(
+                    R.styleable
+                            .AndroidManifestPermissionGroup_backgroundRequestDetail, 0);
+
+            result.requestRes = sa.getResourceId(
+                    R.styleable.AndroidManifestPermissionGroup_request, 0);
+            result.flags = sa.getInt(
+                    R.styleable.AndroidManifestPermissionGroup_permissionGroupFlags,
+                    0);
+            result.priority = sa.getInt(
+                    R.styleable.AndroidManifestPermissionGroup_priority, 0);
+
+        } finally {
+            if (sa != null) {
+                sa.recycle();
+            }
+        }
+
+        boolean success = parseAllMetaData(parsingPackage, res, parser,
+                "<permission-group>", result, outError);
+        if (!success || outError[0] != null) {
+            return null;
+        }
+
+        return result;
+    }
+
+    public static ParsedInstrumentation parseInstrumentation(
+            ParsingPackage parsingPackage,
+            Resources res,
+            XmlResourceParser parser,
+            String[] outError
+    ) throws IOException, XmlPullParserException {
+        TypedArray sa = null;
+        String packageName = parsingPackage.getPackageName();
+        ParsedInstrumentation result = new ParsedInstrumentation();
+
+        try {
+            sa = res.obtainAttributes(parser, R.styleable.AndroidManifestInstrumentation);
+
+            // TODO(b/135203078): Re-share all of the configuration for this. ParseComponentArgs was
+            //  un-used for this, but can be adjusted and re-added to share all the initial result
+            //  parsing for icon/logo/name/etc in all of these parse methods.
+            String name = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestInstrumentation_name, 0);
+            if (name == null) {
+                outError[0] = "<instrumentation> does not specify android:name";
+                return null;
+            } else {
+                String className = ApkParseUtils.buildClassName(packageName, name);
+                if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) {
+                    outError[0] = "<instrumentation> invalid android:name";
+                    return null;
+                } else if (className == null) {
+                    outError[0] = "Empty class name in package " + packageName;
+                    return null;
+                }
+
+                result.className = className;
+            }
+
+            int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId(
+                    R.styleable.AndroidManifestInstrumentation_roundIcon, 0) : 0;
+            if (roundIconVal != 0) {
+                result.icon = roundIconVal;
+                result.nonLocalizedLabel = null;
+            } else {
+                int iconVal = sa.getResourceId(R.styleable.AndroidManifestInstrumentation_icon, 0);
+                if (iconVal != 0) {
+                    result.icon = iconVal;
+                    result.nonLocalizedLabel = null;
+                }
+            }
+
+            int logoVal = sa.getResourceId(R.styleable.AndroidManifestInstrumentation_logo, 0);
+            if (logoVal != 0) {
+                result.logo = logoVal;
+            }
+
+            int bannerVal = sa.getResourceId(R.styleable.AndroidManifestInstrumentation_banner, 0);
+            if (bannerVal != 0) {
+                result.banner = bannerVal;
+            }
+
+            TypedValue v = sa.peekValue(R.styleable.AndroidManifestInstrumentation_label);
+            if (v != null && (result.labelRes = v.resourceId) == 0) {
+                result.nonLocalizedLabel = v.coerceToString();
+            }
+
+            result.setPackageNameInternal(packageName);
+
+            String str;
+            // Note: don't allow this value to be a reference to a resource
+            // that may change.
+            str = sa.getNonResourceString(R.styleable.AndroidManifestInstrumentation_targetPackage);
+            result.setTargetPackage(str);
+
+            str = sa.getNonResourceString(
+                    R.styleable.AndroidManifestInstrumentation_targetProcesses);
+            result.setTargetProcesses(str);
+            result.handleProfiling = sa.getBoolean(
+                    R.styleable.AndroidManifestInstrumentation_handleProfiling, false);
+            result.functionalTest = sa.getBoolean(
+                    R.styleable.AndroidManifestInstrumentation_functionalTest, false);
+
+        } finally {
+            if (sa != null) {
+                sa.recycle();
+            }
+        }
+
+        boolean success = parseAllMetaData(parsingPackage, res, parser,
+                "<instrumentation>", result, outError);
+        if (!success || outError[0] != null) {
+            return null;
+        }
+
+        return result;
+    }
+
+    public static ActivityInfo.WindowLayout parseLayout(Resources res, AttributeSet attrs) {
+        TypedArray sw = res.obtainAttributes(attrs,
+                R.styleable.AndroidManifestLayout);
+        int width = -1;
+        float widthFraction = -1f;
+        int height = -1;
+        float heightFraction = -1f;
+        final int widthType = sw.getType(
+                R.styleable.AndroidManifestLayout_defaultWidth);
+        if (widthType == TypedValue.TYPE_FRACTION) {
+            widthFraction = sw.getFraction(
+                    R.styleable.AndroidManifestLayout_defaultWidth,
+                    1, 1, -1);
+        } else if (widthType == TypedValue.TYPE_DIMENSION) {
+            width = sw.getDimensionPixelSize(
+                    R.styleable.AndroidManifestLayout_defaultWidth,
+                    -1);
+        }
+        final int heightType = sw.getType(
+                R.styleable.AndroidManifestLayout_defaultHeight);
+        if (heightType == TypedValue.TYPE_FRACTION) {
+            heightFraction = sw.getFraction(
+                    R.styleable.AndroidManifestLayout_defaultHeight,
+                    1, 1, -1);
+        } else if (heightType == TypedValue.TYPE_DIMENSION) {
+            height = sw.getDimensionPixelSize(
+                    R.styleable.AndroidManifestLayout_defaultHeight,
+                    -1);
+        }
+        int gravity = sw.getInt(
+                R.styleable.AndroidManifestLayout_gravity,
+                Gravity.CENTER);
+        int minWidth = sw.getDimensionPixelSize(
+                R.styleable.AndroidManifestLayout_minWidth,
+                -1);
+        int minHeight = sw.getDimensionPixelSize(
+                R.styleable.AndroidManifestLayout_minHeight,
+                -1);
+        sw.recycle();
+        return new ActivityInfo.WindowLayout(width, widthFraction,
+                height, heightFraction, gravity, minWidth, minHeight);
+    }
+
+    public static boolean parseIntentInfo(
+            ParsedIntentInfo intentInfo,
+            ParsingPackage parsingPackage,
+            Resources res, XmlResourceParser parser, boolean allowGlobs,
+            boolean allowAutoVerify, String[] outError
+    ) throws XmlPullParserException, IOException {
+        TypedArray sa = res.obtainAttributes(parser,
+                R.styleable.AndroidManifestIntentFilter);
+
+        int priority = sa.getInt(
+                R.styleable.AndroidManifestIntentFilter_priority, 0);
+        intentInfo.setPriority(priority);
+
+        int order = sa.getInt(
+                R.styleable.AndroidManifestIntentFilter_order, 0);
+        intentInfo.setOrder(order);
+
+        TypedValue v = sa.peekValue(
+                R.styleable.AndroidManifestIntentFilter_label);
+        if (v != null && (intentInfo.labelRes = v.resourceId) == 0) {
+            intentInfo.nonLocalizedLabel = v.coerceToString();
+        }
+
+        int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId(
+                R.styleable.AndroidManifestIntentFilter_roundIcon, 0) : 0;
+        if (roundIconVal != 0) {
+            intentInfo.icon = roundIconVal;
+        } else {
+            intentInfo.icon = sa.getResourceId(
+                    R.styleable.AndroidManifestIntentFilter_icon, 0);
+        }
+
+        if (allowAutoVerify) {
+            intentInfo.setAutoVerify(sa.getBoolean(
+                    R.styleable.AndroidManifestIntentFilter_autoVerify,
+                    false));
+        }
+
+        sa.recycle();
+
+        int outerDepth = parser.getDepth();
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                continue;
+            }
+
+            String nodeName = parser.getName();
+            if (nodeName.equals("action")) {
+                String value = parser.getAttributeValue(
+                        PackageParser.ANDROID_RESOURCES, "name");
+                if (TextUtils.isEmpty(value)) {
+                    outError[0] = "No value supplied for <android:name>";
+                    return false;
+                }
+                XmlUtils.skipCurrentTag(parser);
+
+                intentInfo.addAction(value);
+            } else if (nodeName.equals("category")) {
+                String value = parser.getAttributeValue(
+                        PackageParser.ANDROID_RESOURCES, "name");
+                if (TextUtils.isEmpty(value)) {
+                    outError[0] = "No value supplied for <android:name>";
+                    return false;
+                }
+                XmlUtils.skipCurrentTag(parser);
+
+                intentInfo.addCategory(value);
+
+            } else if (nodeName.equals("data")) {
+                sa = res.obtainAttributes(parser,
+                        R.styleable.AndroidManifestData);
+
+                String str = sa.getNonConfigurationString(
+                        R.styleable.AndroidManifestData_mimeType, 0);
+                if (str != null) {
+                    try {
+                        intentInfo.addRawDataType(str);
+                    } catch (IntentFilter.MalformedMimeTypeException e) {
+                        outError[0] = e.toString();
+                        sa.recycle();
+                        return false;
+                    }
+                }
+
+                str = sa.getNonConfigurationString(
+                        R.styleable.AndroidManifestData_scheme, 0);
+                if (str != null) {
+                    intentInfo.addDataScheme(str);
+                }
+
+                str = sa.getNonConfigurationString(
+                        R.styleable.AndroidManifestData_ssp, 0);
+                if (str != null) {
+                    intentInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_LITERAL);
+                }
+
+                str = sa.getNonConfigurationString(
+                        R.styleable.AndroidManifestData_sspPrefix, 0);
+                if (str != null) {
+                    intentInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_PREFIX);
+                }
+
+                str = sa.getNonConfigurationString(
+                        R.styleable.AndroidManifestData_sspPattern, 0);
+                if (str != null) {
+                    if (!allowGlobs) {
+                        outError[0] = "sspPattern not allowed here; ssp must be literal";
+                        return false;
+                    }
+                    intentInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_SIMPLE_GLOB);
+                }
+
+                String host = sa.getNonConfigurationString(
+                        R.styleable.AndroidManifestData_host, 0);
+                String port = sa.getNonConfigurationString(
+                        R.styleable.AndroidManifestData_port, 0);
+                if (host != null) {
+                    intentInfo.addDataAuthority(host, port);
+                }
+
+                str = sa.getNonConfigurationString(
+                        R.styleable.AndroidManifestData_path, 0);
+                if (str != null) {
+                    intentInfo.addDataPath(str, PatternMatcher.PATTERN_LITERAL);
+                }
+
+                str = sa.getNonConfigurationString(
+                        R.styleable.AndroidManifestData_pathPrefix, 0);
+                if (str != null) {
+                    intentInfo.addDataPath(str, PatternMatcher.PATTERN_PREFIX);
+                }
+
+                str = sa.getNonConfigurationString(
+                        R.styleable.AndroidManifestData_pathPattern, 0);
+                if (str != null) {
+                    if (!allowGlobs) {
+                        outError[0] = "pathPattern not allowed here; path must be literal";
+                        return false;
+                    }
+                    intentInfo.addDataPath(str, PatternMatcher.PATTERN_SIMPLE_GLOB);
+                }
+
+                str = sa.getNonConfigurationString(
+                        R.styleable.AndroidManifestData_pathAdvancedPattern, 0);
+                if (str != null) {
+                    if (!allowGlobs) {
+                        outError[0] = "pathAdvancedPattern not allowed here; path must be literal";
+                        return false;
+                    }
+                    intentInfo.addDataPath(str, PatternMatcher.PATTERN_ADVANCED_GLOB);
+                }
+
+                sa.recycle();
+                XmlUtils.skipCurrentTag(parser);
+            } else if (!PackageParser.RIGID_PARSER) {
+                Slog.w(TAG, "Unknown element under <intent-filter>: "
+                        + parser.getName() + " at " + parsingPackage.getBaseCodePath() + " "
+                        + parser.getPositionDescription());
+                XmlUtils.skipCurrentTag(parser);
+            } else {
+                outError[0] = "Bad element under <intent-filter>: " + parser.getName();
+                return false;
+            }
+        }
+
+        intentInfo.hasDefault = intentInfo.hasCategory(Intent.CATEGORY_DEFAULT);
+
+        if (PackageParser.DEBUG_PARSER) {
+            final StringBuilder cats = new StringBuilder("Intent d=");
+            cats.append(intentInfo.hasDefault);
+            cats.append(", cat=");
+
+            final Iterator<String> it = intentInfo.categoriesIterator();
+            if (it != null) {
+                while (it.hasNext()) {
+                    cats.append(' ');
+                    cats.append(it.next());
+                }
+            }
+            Slog.d(TAG, cats.toString());
+        }
+
+        return true;
+    }
+
+    private static boolean parseAllMetaData(
+            ParsingPackage parsingPackage,
+            Resources res, XmlResourceParser parser, String tag,
+            ParsedComponent outInfo,
+            String[] outError
+    ) throws XmlPullParserException, IOException {
+        int outerDepth = parser.getDepth();
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG
+                || parser.getDepth() > outerDepth)) {
+            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                continue;
+            }
+
+            if (parser.getName().equals("meta-data")) {
+                if ((outInfo.metaData = ApkParseUtils.parseMetaData(parsingPackage, res, parser,
+                        outInfo.metaData, outError)) == null) {
+                    return false;
+                }
+            } else {
+                if (!PackageParser.RIGID_PARSER) {
+                    Slog.w(TAG, "Unknown element under " + tag + ": "
+                            + parser.getName() + " at " + parsingPackage.getBaseCodePath() + " "
+                            + parser.getPositionDescription());
+                    XmlUtils.skipCurrentTag(parser);
+                    continue;
+                } else {
+                    outError[0] = "Bad element under " + tag + ": " + parser.getName();
+                }
+            }
+        }
+
+        return true;
+    }
+
+    public static boolean isImplicitlyExposedIntent(IntentFilter intent) {
+        return intent.hasCategory(Intent.CATEGORY_BROWSABLE)
+                || intent.hasAction(Intent.ACTION_SEND)
+                || intent.hasAction(Intent.ACTION_SENDTO)
+                || intent.hasAction(Intent.ACTION_SEND_MULTIPLE);
+    }
+}
diff --git a/core/java/android/content/pm/parsing/PackageImpl.java b/core/java/android/content/pm/parsing/PackageImpl.java
new file mode 100644
index 0000000..363cf80
--- /dev/null
+++ b/core/java/android/content/pm/parsing/PackageImpl.java
@@ -0,0 +1,3213 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.content.pm.parsing;
+
+import static android.os.Build.VERSION_CODES.DONUT;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.ConfigurationInfo;
+import android.content.pm.FeatureGroupInfo;
+import android.content.pm.FeatureInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageParser;
+import android.content.pm.ProviderInfo;
+import android.content.pm.ServiceInfo;
+import android.content.pm.SharedLibraryInfo;
+import android.content.pm.parsing.ComponentParseUtils.ParsedActivity;
+import android.content.pm.parsing.ComponentParseUtils.ParsedActivityIntentInfo;
+import android.content.pm.parsing.ComponentParseUtils.ParsedInstrumentation;
+import android.content.pm.parsing.ComponentParseUtils.ParsedIntentInfo;
+import android.content.pm.parsing.ComponentParseUtils.ParsedPermission;
+import android.content.pm.parsing.ComponentParseUtils.ParsedPermissionGroup;
+import android.content.pm.parsing.ComponentParseUtils.ParsedProvider;
+import android.content.pm.parsing.ComponentParseUtils.ParsedService;
+import android.content.res.TypedArray;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Environment;
+import android.os.Parcel;
+import android.os.UserHandle;
+import android.os.storage.StorageManager;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.SparseArray;
+
+import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ArrayUtils;
+import com.android.server.SystemConfig;
+
+import java.security.PublicKey;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.UUID;
+
+/**
+ * The backing data for a package that was parsed from disk.
+ *
+ * TODO(b/135203078): Convert Lists used as sets into Sets, to better express intended use case
+ * TODO(b/135203078): Field nullability annotations
+ * TODO(b/135203078): Convert = 1 fields into Booleans
+ * TODO(b/135203078): Make all lists nullable and Collections.unmodifiable immutable when returned.
+ *   Prefer add/set methods if adding is necessary.
+ * TODO(b/135203078): Consider comments to disable auto-format and single-line, single-space all the
+ *   get/set methods to make this class far more compact. Maybe even separate some logic into parent
+ *   classes, assuming there is no overhead.
+ * TODO(b/135203078): Copy documentation from PackageParser#Package for the relevant fields included
+ *   here. Should clarify and clean up any differences. Also consider renames if it helps make
+ *   things clearer.
+ * TODO(b/135203078): Intern all possibl e String values? Initial refactor just mirrored old
+ *   behavior.
+ *
+ * @hide
+ */
+public final class PackageImpl implements ParsingPackage, ParsedPackage, AndroidPackage,
+        AndroidPackageWrite {
+
+    private static final String TAG = "PackageImpl";
+
+    // Resource boolean are -1, so 1 means we don't know the value.
+    private int supportsSmallScreens = 1;
+    private int supportsNormalScreens = 1;
+    private int supportsLargeScreens = 1;
+    private int supportsXLargeScreens = 1;
+    private int resizeable = 1;
+    private int anyDensity = 1;
+
+    private long[] lastPackageUsageTimeInMills =
+            new long[PackageManager.NOTIFY_PACKAGE_USE_REASONS_COUNT];
+
+    private int versionCode;
+    private int versionCodeMajor;
+    private int baseRevisionCode;
+    private String versionName;
+
+    private boolean coreApp;
+    private int compileSdkVersion;
+    private String compileSdkVersionCodename;
+
+    private String packageName;
+    private String realPackage;
+    private String manifestPackageName;
+    private String baseCodePath;
+
+    private boolean requiredForAllUsers;
+    private String restrictedAccountType;
+    private String requiredAccountType;
+
+    private boolean baseHardwareAccelerated;
+
+    private String overlayTarget;
+    private String overlayTargetName;
+    private String overlayCategory;
+    private int overlayPriority;
+    private boolean overlayIsStatic;
+
+    private String staticSharedLibName;
+    private long staticSharedLibVersion;
+    private ArrayList<String> libraryNames;
+    private ArrayList<String> usesLibraries;
+    private ArrayList<String> usesOptionalLibraries;
+
+    private ArrayList<String> usesStaticLibraries;
+    private long[] usesStaticLibrariesVersions;
+    private String[][] usesStaticLibrariesCertDigests;
+
+    private String sharedUserId;
+
+    private int sharedUserLabel;
+    private ArrayList<ConfigurationInfo> configPreferences;
+    private ArrayList<FeatureInfo> reqFeatures;
+    private ArrayList<FeatureGroupInfo> featureGroups;
+
+    private byte[] restrictUpdateHash;
+
+    private ArrayList<String> originalPackages;
+    private ArrayList<String> adoptPermissions;
+
+    private ArrayList<String> requestedPermissions;
+    private ArrayList<String> implicitPermissions;
+
+    private ArraySet<String> upgradeKeySets;
+    private Map<String, ArraySet<PublicKey>> keySetMapping;
+
+    private ArrayList<String> protectedBroadcasts;
+
+    @Nullable
+    private ArrayList<ComponentParseUtils.ParsedActivity> activities;
+
+    @Nullable
+    private ArrayList<ComponentParseUtils.ParsedActivity> receivers;
+
+    @Nullable
+    private ArrayList<ComponentParseUtils.ParsedService> services;
+
+    @Nullable
+    private ArrayList<ComponentParseUtils.ParsedProvider> providers;
+
+    @Nullable
+    private ArrayList<ComponentParseUtils.ParsedPermission> permissions;
+
+    @Nullable
+    private ArrayList<ComponentParseUtils.ParsedPermissionGroup> permissionGroups;
+
+    @Nullable
+    private ArrayList<ComponentParseUtils.ParsedInstrumentation> instrumentations;
+
+    private ArrayList<ParsedActivityIntentInfo> preferredActivityFilters;
+
+    private Bundle appMetaData;
+
+    private String volumeUuid;
+    private String applicationVolumeUuid;
+    private PackageParser.SigningDetails signingDetails;
+
+    private String codePath;
+
+    private boolean use32BitAbi;
+    private boolean visibleToInstantApps;
+
+    private String cpuAbiOverride;
+
+    private boolean isStub;
+
+    // TODO(b/135203078): Remove, should be unused
+    private int preferredOrder;
+
+    private boolean forceQueryable;
+
+    @Nullable
+    private ArrayList<Intent> queriesIntents;
+
+    @Nullable
+    private ArrayList<String> queriesPackages;
+
+    private String[] splitClassLoaderNames;
+    private String[] splitCodePaths;
+    private SparseArray<int[]> splitDependencies;
+    private int[] splitFlags;
+    private String[] splitNames;
+    private int[] splitRevisionCodes;
+
+    // TODO(b/135203078): Audit applicationInfo.something usages, which may be different from
+    //  package.something usages. There were differing cases of package.field = versus
+    //  package.appInfo.field =. This class assumes some obvious ones, like packageName,
+    //  were collapsible, but kept the following separate.
+
+    private String applicationInfoBaseResourcePath;
+    private String applicationInfoCodePath;
+    private String applicationInfoResourcePath;
+    private String[] applicationInfoSplitResourcePaths;
+
+    private String appComponentFactory;
+    private String backupAgentName;
+    private int banner;
+    private int category;
+    private String classLoaderName;
+    private String className;
+    private int compatibleWidthLimitDp;
+    private String credentialProtectedDataDir;
+    private String dataDir;
+    private int descriptionRes;
+    private String deviceProtectedDataDir;
+    private boolean enabled;
+    private int flags;
+    private int fullBackupContent;
+    private boolean hiddenUntilInstalled;
+    private int icon;
+    private int iconRes;
+    private int installLocation = PackageParser.PARSE_DEFAULT_INSTALL_LOCATION;
+    private int labelRes;
+    private int largestWidthLimitDp;
+    private int logo;
+    private String manageSpaceActivityName;
+    private float maxAspectRatio;
+    private float minAspectRatio;
+    private int minSdkVersion;
+    private String name;
+    private String nativeLibraryDir;
+    private String nativeLibraryRootDir;
+    private boolean nativeLibraryRootRequiresIsa;
+    private int networkSecurityConfigRes;
+    private CharSequence nonLocalizedLabel;
+    private String permission;
+    private String primaryCpuAbi;
+    private int privateFlags;
+    private String processName;
+    private int requiresSmallestWidthDp;
+    private int roundIconRes;
+    private String secondaryCpuAbi;
+    private String secondaryNativeLibraryDir;
+    private String seInfo;
+    private String seInfoUser;
+    private int targetSandboxVersion;
+    private int targetSdkVersion;
+    private String taskAffinity;
+    private int theme;
+    private int uid = -1;
+    private int uiOptions;
+    private String[] usesLibraryFiles;
+    private List<SharedLibraryInfo> usesLibraryInfos;
+    private String zygotePreloadName;
+
+    @VisibleForTesting
+    public PackageImpl(
+            String packageName,
+            String baseCodePath,
+            TypedArray manifestArray,
+            boolean isCoreApp
+    ) {
+        this.packageName = TextUtils.safeIntern(packageName);
+        this.manifestPackageName = this.packageName;
+        this.baseCodePath = baseCodePath;
+
+        this.versionCode = manifestArray.getInteger(R.styleable.AndroidManifest_versionCode, 0);
+        this.versionCodeMajor = manifestArray.getInteger(
+                R.styleable.AndroidManifest_versionCodeMajor, 0);
+        this.baseRevisionCode = manifestArray.getInteger(R.styleable.AndroidManifest_revisionCode,
+                0);
+        setVersionName(manifestArray.getNonConfigurationString(
+                R.styleable.AndroidManifest_versionName, 0));
+        this.coreApp = isCoreApp;
+
+        this.compileSdkVersion = manifestArray.getInteger(
+                R.styleable.AndroidManifest_compileSdkVersion, 0);
+        setCompileSdkVersionCodename(manifestArray.getNonConfigurationString(
+                R.styleable.AndroidManifest_compileSdkVersionCodename, 0));
+    }
+
+    private PackageImpl(String packageName) {
+        this.packageName = TextUtils.safeIntern(packageName);
+        this.manifestPackageName = this.packageName;
+    }
+
+    @VisibleForTesting
+    public static ParsingPackage forParsing(String packageName) {
+        return new PackageImpl(packageName);
+    }
+
+    @VisibleForTesting
+    public static ParsingPackage forParsing(
+            String packageName,
+            String baseCodePath,
+            TypedArray manifestArray,
+            boolean isCoreApp) {
+        return new PackageImpl(packageName, baseCodePath, manifestArray, isCoreApp);
+    }
+
+    /**
+     * Mock an unavailable {@link AndroidPackage} to use when removing a package from the system.
+     * This can occur if the package was installed on a storage device that has since been removed.
+     * Since the infrastructure uses {@link AndroidPackage}, but for this case only cares about
+     * volumeUuid, just fake it rather than having separate method paths.
+     */
+    public static AndroidPackage buildFakeForDeletion(String packageName, String volumeUuid) {
+        return new PackageImpl(packageName)
+                .setVolumeUuid(volumeUuid)
+                .hideAsParsed()
+                .hideAsFinal();
+    }
+
+    @Override
+    public ParsedPackage hideAsParsed() {
+        return this;
+    }
+
+    @Override
+    public AndroidPackage hideAsFinal() {
+        updateFlags();
+        return this;
+    }
+
+    @Override
+    @Deprecated
+    public AndroidPackageWrite mutate() {
+        return this;
+    }
+
+    private void updateFlags() {
+        if (supportsSmallScreens < 0 || (supportsSmallScreens > 0
+                && targetSdkVersion
+                >= Build.VERSION_CODES.DONUT)) {
+            this.flags |= ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS;
+        }
+        if (supportsNormalScreens != 0) {
+            this.flags |= ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS;
+        }
+        if (supportsLargeScreens < 0 || (supportsLargeScreens > 0
+                && targetSdkVersion
+                >= Build.VERSION_CODES.DONUT)) {
+            this.flags |= ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS;
+        }
+        if (supportsXLargeScreens < 0 || (supportsXLargeScreens > 0
+                && targetSdkVersion
+                >= Build.VERSION_CODES.GINGERBREAD)) {
+            this.flags |= ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS;
+        }
+        if (resizeable < 0 || (resizeable > 0
+                && targetSdkVersion
+                >= Build.VERSION_CODES.DONUT)) {
+            this.flags |= ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS;
+        }
+        if (anyDensity < 0 || (anyDensity > 0
+                && targetSdkVersion
+                >= Build.VERSION_CODES.DONUT)) {
+            this.flags |= ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES;
+        }
+    }
+
+    @Override
+    public boolean usesCompatibilityMode() {
+        int flags = 0;
+
+        if (supportsSmallScreens < 0 || (supportsSmallScreens > 0
+                && targetSdkVersion
+                >= Build.VERSION_CODES.DONUT)) {
+            flags |= ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS;
+        }
+        if (supportsNormalScreens != 0) {
+            flags |= ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS;
+        }
+        if (supportsLargeScreens < 0 || (supportsLargeScreens > 0
+                && targetSdkVersion
+                >= Build.VERSION_CODES.DONUT)) {
+            flags |= ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS;
+        }
+        if (supportsXLargeScreens < 0 || (supportsXLargeScreens > 0
+                && targetSdkVersion
+                >= Build.VERSION_CODES.GINGERBREAD)) {
+            flags |= ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS;
+        }
+        if (resizeable < 0 || (resizeable > 0
+                && targetSdkVersion
+                >= Build.VERSION_CODES.DONUT)) {
+            flags |= ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS;
+        }
+        if (anyDensity < 0 || (anyDensity > 0
+                && targetSdkVersion
+                >= Build.VERSION_CODES.DONUT)) {
+            flags |= ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES;
+        }
+
+        return targetSdkVersion < DONUT
+                || (flags & (ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS
+                        | ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS
+                        | ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS
+                        | ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS
+                        | ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES
+                        | ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS)) == 0;
+    }
+
+    @Override
+    public String getBaseCodePath() {
+        return baseCodePath;
+    }
+
+    @Override
+    public int getTargetSdkVersion() {
+        return targetSdkVersion;
+    }
+
+    @Override
+    public String getPackageName() {
+        return packageName;
+    }
+
+    @Override
+    public String getProcessName() {
+        return processName;
+    }
+
+    @Override
+    public String getPermission() {
+        return permission;
+    }
+
+    @Override
+    public String getStaticSharedLibName() {
+        return staticSharedLibName;
+    }
+
+    @Override
+    public long getStaticSharedLibVersion() {
+        return staticSharedLibVersion;
+    }
+
+    @Override
+    public String getSharedUserId() {
+        return sharedUserId;
+    }
+
+    @Override
+    public List<String> getRequestedPermissions() {
+        return requestedPermissions == null ? Collections.emptyList() : requestedPermissions;
+    }
+
+    @Nullable
+    @Override
+    public List<ParsedInstrumentation> getInstrumentations() {
+        return instrumentations;
+    }
+
+    @Override
+    public Map<String, ArraySet<PublicKey>> getKeySetMapping() {
+        return keySetMapping == null ? Collections.emptyMap() : keySetMapping;
+    }
+
+    @Override
+    public float getMaxAspectRatio() {
+        return maxAspectRatio;
+    }
+
+    @Override
+    public float getMinAspectRatio() {
+        return minAspectRatio;
+    }
+
+    @NonNull
+    @Override
+    public List<String> getLibraryNames() {
+        return libraryNames == null ? Collections.emptyList() : libraryNames;
+    }
+
+    @Override
+    public List<ParsedActivity> getActivities() {
+        return activities == null ? Collections.emptyList()
+                : activities;
+    }
+
+    @Override
+    public Bundle getAppMetaData() {
+        return appMetaData;
+    }
+
+    @Nullable
+    @Override
+    public List<String> getUsesLibraries() {
+        return usesLibraries;
+    }
+
+    @Nullable
+    @Override
+    public List<String> getUsesStaticLibraries() {
+        return usesStaticLibraries;
+    }
+
+    @Override
+    public boolean isBaseHardwareAccelerated() {
+        return baseHardwareAccelerated;
+    }
+
+    @Override
+    public int getUiOptions() {
+        return uiOptions;
+    }
+
+    // TODO(b/135203078): Checking flags directly can be error prone,
+    //  consider separate interface methods?
+    @Override
+    public int getFlags() {
+        return flags;
+    }
+
+    // TODO(b/135203078): Checking flags directly can be error prone,
+    //  consider separate interface methods?
+    @Override
+    public int getPrivateFlags() {
+        return privateFlags;
+    }
+
+    @Override
+    public String getTaskAffinity() {
+        return taskAffinity;
+    }
+
+    @Nullable
+    @Override
+    public List<String> getOriginalPackages() {
+        return originalPackages;
+    }
+
+    @Override
+    public PackageParser.SigningDetails getSigningDetails() {
+        return signingDetails;
+    }
+
+    @Override
+    public String getVolumeUuid() {
+        return volumeUuid;
+    }
+
+    @Nullable
+    @Override
+    public List<ParsedPermissionGroup> getPermissionGroups() {
+        return permissionGroups;
+    }
+
+    @Nullable
+    @Override
+    public List<ParsedPermission> getPermissions() {
+        return permissions;
+    }
+
+    @Override
+    public String getCpuAbiOverride() {
+        return cpuAbiOverride;
+    }
+
+    @Override
+    public String getPrimaryCpuAbi() {
+        return primaryCpuAbi;
+    }
+
+    @Override
+    public String getSecondaryCpuAbi() {
+        return secondaryCpuAbi;
+    }
+
+    @Override
+    public boolean isUse32BitAbi() {
+        return use32BitAbi;
+    }
+
+    @Override
+    public boolean isForceQueryable() {
+        return forceQueryable;
+    }
+
+    @Override
+    public String getCodePath() {
+        return codePath;
+    }
+
+    @Override
+    public String getNativeLibraryDir() {
+        return nativeLibraryDir;
+    }
+
+    @Override
+    public String getNativeLibraryRootDir() {
+        return nativeLibraryRootDir;
+    }
+
+    @Override
+    public boolean isNativeLibraryRootRequiresIsa() {
+        return nativeLibraryRootRequiresIsa;
+    }
+
+    // TODO(b/135203078): Does nothing, remove?
+    @Override
+    public int getPreferredOrder() {
+        return preferredOrder;
+    }
+
+    @Override
+    public long getLongVersionCode() {
+        return PackageInfo.composeLongVersionCode(versionCodeMajor, versionCode);
+    }
+
+    @Override
+    public PackageImpl setIsOverlay(boolean isOverlay) {
+        this.privateFlags = isOverlay
+                ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_IS_RESOURCE_OVERLAY
+                : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_IS_RESOURCE_OVERLAY;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setExternalStorage(boolean externalStorage) {
+        this.flags = externalStorage
+                ? this.flags | ApplicationInfo.FLAG_EXTERNAL_STORAGE
+                : this.flags & ~ApplicationInfo.FLAG_EXTERNAL_STORAGE;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setIsolatedSplitLoading(boolean isolatedSplitLoading) {
+        this.privateFlags = isolatedSplitLoading
+                ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_ISOLATED_SPLIT_LOADING
+                : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_ISOLATED_SPLIT_LOADING;
+        return this;
+    }
+
+    @Override
+    public PackageImpl sortActivities() {
+        Collections.sort(this.activities, (a1, a2) -> Integer.compare(a2.order, a1.order));
+        return this;
+    }
+
+    @Override
+    public PackageImpl sortReceivers() {
+        Collections.sort(this.receivers, (a1, a2) -> Integer.compare(a2.order, a1.order));
+        return this;
+    }
+
+    @Override
+    public PackageImpl sortServices() {
+        Collections.sort(this.services, (a1, a2) -> Integer.compare(a2.order, a1.order));
+        return this;
+    }
+
+    @Override
+    public PackageImpl setBaseRevisionCode(int baseRevisionCode) {
+        this.baseRevisionCode = baseRevisionCode;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setPreferredOrder(int preferredOrder) {
+        this.preferredOrder = preferredOrder;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setVersionName(String versionName) {
+        this.versionName = TextUtils.safeIntern(versionName);
+        return this;
+    }
+
+    @Override
+    public ParsingPackage setCompileSdkVersion(int compileSdkVersion) {
+        this.compileSdkVersion = compileSdkVersion;
+        return this;
+    }
+
+    @Override
+    public ParsingPackage setCompileSdkVersionCodename(String compileSdkVersionCodename) {
+        this.compileSdkVersionCodename = TextUtils.safeIntern(compileSdkVersionCodename);
+        return this;
+    }
+
+    @Override
+    public PackageImpl setMaxAspectRatio(float maxAspectRatio) {
+        this.maxAspectRatio = maxAspectRatio;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setMinAspectRatio(float minAspectRatio) {
+        this.minAspectRatio = minAspectRatio;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setMinSdkVersion(int minSdkVersion) {
+        this.minSdkVersion = minSdkVersion;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setTargetSdkVersion(int targetSdkVersion) {
+        this.targetSdkVersion = targetSdkVersion;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setRealPackage(String realPackage) {
+        this.realPackage = realPackage;
+        return this;
+    }
+
+    @Override
+    public PackageImpl addConfigPreference(ConfigurationInfo configPreference) {
+        this.configPreferences = ArrayUtils.add(this.configPreferences, configPreference);
+        return this;
+    }
+
+    @Override
+    public PackageImpl addReqFeature(FeatureInfo reqFeature) {
+        this.reqFeatures = ArrayUtils.add(this.reqFeatures, reqFeature);
+        return this;
+    }
+
+    @Override
+    public PackageImpl addFeatureGroup(FeatureGroupInfo featureGroup) {
+        this.featureGroups = ArrayUtils.add(this.featureGroups, featureGroup);
+        return this;
+    }
+
+    @Override
+    public PackageImpl addProtectedBroadcast(String protectedBroadcast) {
+        if (this.protectedBroadcasts == null
+                || !this.protectedBroadcasts.contains(protectedBroadcast)) {
+            this.protectedBroadcasts = ArrayUtils.add(this.protectedBroadcasts,
+                    TextUtils.safeIntern(protectedBroadcast));
+        }
+        return this;
+    }
+
+    @Override
+    public PackageImpl addInstrumentation(ParsedInstrumentation instrumentation) {
+        this.instrumentations = ArrayUtils.add(this.instrumentations, instrumentation);
+        return this;
+    }
+
+    @Override
+    public PackageImpl addOriginalPackage(String originalPackage) {
+        this.originalPackages = ArrayUtils.add(this.originalPackages, originalPackage);
+        return this;
+    }
+
+    @Override
+    public PackageImpl addAdoptPermission(String adoptPermission) {
+        this.adoptPermissions = ArrayUtils.add(this.adoptPermissions, adoptPermission);
+        return this;
+    }
+
+    @Override
+    public PackageImpl addPermission(ParsedPermission permission) {
+        this.permissions = ArrayUtils.add(this.permissions, permission);
+        return this;
+    }
+
+    @Override
+    public PackageImpl removePermission(int index) {
+        this.permissions.remove(index);
+        return this;
+    }
+
+    @Override
+    public PackageImpl addPermissionGroup(ParsedPermissionGroup permissionGroup) {
+        this.permissionGroups = ArrayUtils.add(this.permissionGroups, permissionGroup);
+        return this;
+    }
+
+    @Override
+    public PackageImpl addRequestedPermission(String permission) {
+        this.requestedPermissions = ArrayUtils.add(this.requestedPermissions,
+                TextUtils.safeIntern(permission));
+        return this;
+    }
+
+    @Override
+    public PackageImpl addImplicitPermission(String permission) {
+        this.implicitPermissions = ArrayUtils.add(this.implicitPermissions,
+                TextUtils.safeIntern(permission));
+        return this;
+    }
+
+    @Override
+    public PackageImpl addKeySet(String keySetName, PublicKey publicKey) {
+        if (keySetMapping == null) {
+            keySetMapping = new ArrayMap<>();
+        }
+
+        ArraySet<PublicKey> publicKeys = keySetMapping.get(keySetName);
+        if (publicKeys == null) {
+            publicKeys = new ArraySet<>();
+            keySetMapping.put(keySetName, publicKeys);
+        }
+
+        publicKeys.add(publicKey);
+
+        return this;
+    }
+
+    @Override
+    public ParsingPackage addActivity(ParsedActivity parsedActivity) {
+        this.activities = ArrayUtils.add(this.activities, parsedActivity);
+        return this;
+    }
+
+    @Override
+    public ParsingPackage addReceiver(ParsedActivity parsedReceiver) {
+        this.receivers = ArrayUtils.add(this.receivers, parsedReceiver);
+        return this;
+    }
+
+    @Override
+    public ParsingPackage addService(ParsedService parsedService) {
+        this.services = ArrayUtils.add(this.services, parsedService);
+        return this;
+    }
+
+    @Override
+    public ParsingPackage addProvider(ParsedProvider parsedProvider) {
+        this.providers = ArrayUtils.add(this.providers, parsedProvider);
+        return this;
+    }
+
+    @Override
+    public PackageImpl addLibraryName(String libraryName) {
+        this.libraryNames = ArrayUtils.add(this.libraryNames, TextUtils.safeIntern(libraryName));
+        return this;
+    }
+
+    @Override
+    public PackageImpl addUsesLibrary(String libraryName) {
+        this.usesLibraries = ArrayUtils.add(this.usesLibraries, TextUtils.safeIntern(libraryName));
+        return this;
+    }
+
+    @Override
+    public PackageImpl addUsesOptionalLibrary(String libraryName) {
+        this.usesOptionalLibraries = ArrayUtils.add(this.usesOptionalLibraries,
+                TextUtils.safeIntern(libraryName));
+        return this;
+    }
+
+    @Override
+    public PackageImpl removeUsesOptionalLibrary(String libraryName) {
+        this.usesOptionalLibraries = ArrayUtils.remove(this.usesOptionalLibraries, libraryName);
+        return this;
+    }
+
+    @Override
+    public PackageImpl addUsesStaticLibrary(String libraryName) {
+        this.usesStaticLibraries = ArrayUtils.add(this.usesStaticLibraries,
+                TextUtils.safeIntern(libraryName));
+        return this;
+    }
+
+    @Override
+    public PackageImpl addUsesStaticLibraryVersion(long version) {
+        this.usesStaticLibrariesVersions = ArrayUtils.appendLong(this.usesStaticLibrariesVersions,
+                version, true);
+        return this;
+    }
+
+    @Override
+    public PackageImpl addUsesStaticLibraryCertDigests(String[] certSha256Digests) {
+        this.usesStaticLibrariesCertDigests = ArrayUtils.appendElement(String[].class,
+                this.usesStaticLibrariesCertDigests, certSha256Digests, true);
+        return this;
+    }
+
+    @Override
+    public PackageImpl addPreferredActivityFilter(
+            ParsedActivityIntentInfo parsedActivityIntentInfo) {
+        this.preferredActivityFilters = ArrayUtils.add(this.preferredActivityFilters,
+                parsedActivityIntentInfo);
+        return this;
+    }
+
+    @Override
+    public PackageImpl addQueriesIntent(Intent intent) {
+        this.queriesIntents = ArrayUtils.add(this.queriesIntents, intent);
+        return this;
+    }
+
+    @Override
+    public PackageImpl addQueriesPackage(String packageName) {
+        this.queriesPackages = ArrayUtils.add(this.queriesPackages,
+                TextUtils.safeIntern(packageName));
+        return this;
+    }
+
+    @Override
+    public PackageImpl setSupportsSmallScreens(int supportsSmallScreens) {
+        if (supportsSmallScreens == 1) {
+            return this;
+        }
+
+        this.supportsSmallScreens = supportsSmallScreens;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setSupportsNormalScreens(int supportsNormalScreens) {
+        if (supportsNormalScreens == 1) {
+            return this;
+        }
+
+        this.supportsNormalScreens = supportsNormalScreens;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setSupportsLargeScreens(int supportsLargeScreens) {
+        if (supportsLargeScreens == 1) {
+            return this;
+        }
+
+        this.supportsLargeScreens = supportsLargeScreens;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setSupportsXLargeScreens(int supportsXLargeScreens) {
+        if (supportsXLargeScreens == 1) {
+            return this;
+        }
+
+        this.supportsXLargeScreens = supportsXLargeScreens;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setResizeable(int resizeable) {
+        if (resizeable == 1) {
+            return this;
+        }
+
+        this.resizeable = resizeable;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setAnyDensity(int anyDensity) {
+        if (anyDensity == 1) {
+            return this;
+        }
+
+        this.anyDensity = anyDensity;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setRequiresSmallestWidthDp(int requiresSmallestWidthDp) {
+        this.requiresSmallestWidthDp = requiresSmallestWidthDp;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setCompatibleWidthLimitDp(int compatibleWidthLimitDp) {
+        this.compatibleWidthLimitDp = compatibleWidthLimitDp;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setLargestWidthLimitDp(int largestWidthLimitDp) {
+        this.largestWidthLimitDp = largestWidthLimitDp;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setInstallLocation(int installLocation) {
+        this.installLocation = installLocation;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setTargetSandboxVersion(int targetSandboxVersion) {
+        this.targetSandboxVersion = targetSandboxVersion;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setRequiredForAllUsers(boolean requiredForAllUsers) {
+        this.requiredForAllUsers = requiredForAllUsers;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setRestrictedAccountType(String restrictedAccountType) {
+        this.restrictedAccountType = restrictedAccountType;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setRequiredAccountType(String requiredAccountType) {
+        this.requiredAccountType = requiredAccountType;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setBaseHardwareAccelerated(boolean baseHardwareAccelerated) {
+        this.baseHardwareAccelerated = baseHardwareAccelerated;
+
+        this.flags = baseHardwareAccelerated
+                ? this.flags | ApplicationInfo.FLAG_HARDWARE_ACCELERATED
+                : this.flags & ~ApplicationInfo.FLAG_HARDWARE_ACCELERATED;
+
+        return this;
+    }
+
+    @Override
+    public PackageImpl setHasDomainUrls(boolean hasDomainUrls) {
+        this.privateFlags = hasDomainUrls
+                ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS
+                : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setAppMetaData(Bundle appMetaData) {
+        this.appMetaData = appMetaData;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setOverlayTarget(String overlayTarget) {
+        this.overlayTarget = overlayTarget;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setOverlayTargetName(String overlayTargetName) {
+        this.overlayTargetName = overlayTargetName;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setOverlayCategory(String overlayCategory) {
+        this.overlayCategory = overlayCategory;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setOverlayPriority(int overlayPriority) {
+        this.overlayPriority = overlayPriority;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setOverlayIsStatic(boolean overlayIsStatic) {
+        this.overlayIsStatic = overlayIsStatic;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setStaticSharedLibName(String staticSharedLibName) {
+        this.staticSharedLibName = TextUtils.safeIntern(staticSharedLibName);
+        return this;
+    }
+
+    @Override
+    public PackageImpl setStaticSharedLibVersion(long staticSharedLibVersion) {
+        this.staticSharedLibVersion = staticSharedLibVersion;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setSharedUserId(String sharedUserId) {
+        this.sharedUserId = TextUtils.safeIntern(sharedUserId);
+        return this;
+    }
+
+    @Override
+    public PackageImpl setSharedUserLabel(int sharedUserLabel) {
+        this.sharedUserLabel = sharedUserLabel;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setRestrictUpdateHash(byte[] restrictUpdateHash) {
+        this.restrictUpdateHash = restrictUpdateHash;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setUpgradeKeySets(ArraySet<String> upgradeKeySets) {
+        this.upgradeKeySets = upgradeKeySets;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setVolumeUuid(String volumeUuid) {
+        this.volumeUuid = volumeUuid;
+        return this;
+    }
+
+    @Deprecated
+    @Override
+    public PackageImpl setApplicationVolumeUuid(String applicationVolumeUuid) {
+        this.applicationVolumeUuid = applicationVolumeUuid;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setSigningDetails(PackageParser.SigningDetails signingDetails) {
+        this.signingDetails = signingDetails;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setCodePath(String codePath) {
+        this.codePath = codePath;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setUse32BitAbi(boolean use32BitAbi) {
+        this.use32BitAbi = use32BitAbi;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setCpuAbiOverride(String cpuAbiOverride) {
+        this.cpuAbiOverride = cpuAbiOverride;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setForceQueryable(boolean forceQueryable) {
+        this.forceQueryable = forceQueryable;
+        return this;
+    }
+
+    // TODO(b/135203078): Remove and move PackageManagerService#renameStaticSharedLibraryPackage
+    //  into initial package parsing
+    @Override
+    public PackageImpl setPackageName(String packageName) {
+        this.packageName = packageName.intern();
+
+        if (permissions != null) {
+            for (ParsedPermission permission : permissions) {
+                permission.setPackageName(this.packageName);
+            }
+        }
+
+        if (permissionGroups != null) {
+            for (ParsedPermissionGroup permissionGroup : permissionGroups) {
+                permissionGroup.setPackageName(this.packageName);
+            }
+        }
+
+        if (activities != null) {
+            for (ParsedActivity parsedActivity : activities) {
+                parsedActivity.setPackageName(this.packageName);
+            }
+        }
+
+        if (receivers != null) {
+            for (ParsedActivity receiver : receivers) {
+                receiver.setPackageName(this.packageName);
+            }
+        }
+
+        if (providers != null) {
+            for (ParsedProvider provider : providers) {
+                provider.setPackageName(this.packageName);
+            }
+        }
+
+        if (services != null) {
+            for (ParsedService service : services) {
+                service.setPackageName(this.packageName);
+            }
+        }
+
+        if (instrumentations != null) {
+            for (ParsedInstrumentation instrumentation : instrumentations) {
+                instrumentation.setPackageName(this.packageName);
+            }
+        }
+
+        return this;
+    }
+
+    // Under this is parseBaseApplication
+
+    @Override
+    public PackageImpl setAllowBackup(boolean allowBackup) {
+        this.flags = allowBackup
+                ? this.flags | ApplicationInfo.FLAG_ALLOW_BACKUP
+                : this.flags & ~ApplicationInfo.FLAG_ALLOW_BACKUP;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setKillAfterRestore(boolean killAfterRestore) {
+        this.flags = killAfterRestore
+                ? this.flags | ApplicationInfo.FLAG_KILL_AFTER_RESTORE
+                : this.flags & ~ApplicationInfo.FLAG_KILL_AFTER_RESTORE;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setRestoreAnyVersion(boolean restoreAnyVersion) {
+        this.flags = restoreAnyVersion
+                ? this.flags | ApplicationInfo.FLAG_RESTORE_ANY_VERSION
+                : this.flags & ~ApplicationInfo.FLAG_RESTORE_ANY_VERSION;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setFullBackupOnly(boolean fullBackupOnly) {
+        this.flags = fullBackupOnly
+                ? this.flags | ApplicationInfo.FLAG_FULL_BACKUP_ONLY
+                : this.flags & ~ApplicationInfo.FLAG_FULL_BACKUP_ONLY;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setPersistent(boolean persistent) {
+        this.flags = persistent
+                ? this.flags | ApplicationInfo.FLAG_PERSISTENT
+                : this.flags & ~ApplicationInfo.FLAG_PERSISTENT;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setDebuggable(boolean debuggable) {
+        this.flags = debuggable
+                ? this.flags | ApplicationInfo.FLAG_DEBUGGABLE
+                : this.flags & ~ApplicationInfo.FLAG_DEBUGGABLE;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setProfileableByShell(boolean profileableByShell) {
+        this.privateFlags = profileableByShell
+                ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_PROFILEABLE_BY_SHELL
+                : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_PROFILEABLE_BY_SHELL;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setVmSafeMode(boolean vmSafeMode) {
+        this.flags = vmSafeMode
+                ? this.flags | ApplicationInfo.FLAG_VM_SAFE_MODE
+                : this.flags & ~ApplicationInfo.FLAG_VM_SAFE_MODE;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setHasCode(boolean hasCode) {
+        this.flags = hasCode
+                ? this.flags | ApplicationInfo.FLAG_HAS_CODE
+                : this.flags & ~ApplicationInfo.FLAG_HAS_CODE;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setAllowTaskReparenting(boolean allowTaskReparenting) {
+        this.flags = allowTaskReparenting
+                ? this.flags | ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING
+                : this.flags & ~ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setAllowClearUserData(boolean allowClearUserData) {
+        this.flags = allowClearUserData
+                ? this.flags | ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA
+                : this.flags & ~ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setLargeHeap(boolean largeHeap) {
+        this.flags = largeHeap
+                ? this.flags | ApplicationInfo.FLAG_LARGE_HEAP
+                : this.flags & ~ApplicationInfo.FLAG_LARGE_HEAP;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setUsesCleartextTraffic(boolean usesCleartextTraffic) {
+        this.flags = usesCleartextTraffic
+                ? this.flags | ApplicationInfo.FLAG_USES_CLEARTEXT_TRAFFIC
+                : this.flags & ~ApplicationInfo.FLAG_USES_CLEARTEXT_TRAFFIC;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setSupportsRtl(boolean supportsRtl) {
+        this.flags = supportsRtl
+                ? this.flags | ApplicationInfo.FLAG_SUPPORTS_RTL
+                : this.flags & ~ApplicationInfo.FLAG_SUPPORTS_RTL;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setTestOnly(boolean testOnly) {
+        this.flags = testOnly
+                ? this.flags | ApplicationInfo.FLAG_TEST_ONLY
+                : this.flags & ~ApplicationInfo.FLAG_TEST_ONLY;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setMultiArch(boolean multiArch) {
+        this.flags = multiArch
+                ? this.flags | ApplicationInfo.FLAG_MULTIARCH
+                : this.flags & ~ApplicationInfo.FLAG_MULTIARCH;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setExtractNativeLibs(boolean extractNativeLibs) {
+        this.flags = extractNativeLibs
+                ? this.flags | ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS
+                : this.flags & ~ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setIsGame(boolean isGame) {
+        this.flags = isGame
+                ? this.flags | ApplicationInfo.FLAG_IS_GAME
+                : this.flags & ~ApplicationInfo.FLAG_IS_GAME;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setBackupInForeground(boolean backupInForeground) {
+        this.privateFlags = backupInForeground
+                ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_BACKUP_IN_FOREGROUND
+                : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_BACKUP_IN_FOREGROUND;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setUseEmbeddedDex(boolean useEmbeddedDex) {
+        this.privateFlags = useEmbeddedDex
+                ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_USE_EMBEDDED_DEX
+                : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_USE_EMBEDDED_DEX;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setDefaultToDeviceProtectedStorage(boolean defaultToDeviceProtectedStorage) {
+        this.privateFlags = defaultToDeviceProtectedStorage
+                ? this.privateFlags | ApplicationInfo
+                        .PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE
+                : this.privateFlags & ~ApplicationInfo
+                        .PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setDirectBootAware(boolean directBootAware) {
+        this.privateFlags = directBootAware
+                ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE
+                : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setPartiallyDirectBootAware(boolean partiallyDirectBootAware) {
+        this.privateFlags = partiallyDirectBootAware
+                ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE
+                : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setActivitiesResizeModeResizeableViaSdkVersion(
+            boolean resizeableViaSdkVersion
+    ) {
+        this.privateFlags = resizeableViaSdkVersion
+                ? this.privateFlags | ApplicationInfo
+                        .PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION
+                : this.privateFlags & ~ApplicationInfo
+                        .PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setActivitiesResizeModeResizeable(boolean resizeable) {
+        this.privateFlags = resizeable
+                ? this.privateFlags | ApplicationInfo
+                        .PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE
+                : this.privateFlags & ~ApplicationInfo
+                        .PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE;
+
+        this.privateFlags = !resizeable
+                ? this.privateFlags | ApplicationInfo
+                        .PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE
+                : this.privateFlags & ~ApplicationInfo
+                        .PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setAllowClearUserDataOnFailedRestore(
+            boolean allowClearUserDataOnFailedRestore
+    ) {
+        this.privateFlags = allowClearUserDataOnFailedRestore
+                ? this.privateFlags | ApplicationInfo
+                        .PRIVATE_FLAG_ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE
+                : this.privateFlags & ~ApplicationInfo
+                        .PRIVATE_FLAG_ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setAllowAudioPlaybackCapture(boolean allowAudioPlaybackCapture) {
+        this.privateFlags = allowAudioPlaybackCapture
+                ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_ALLOW_AUDIO_PLAYBACK_CAPTURE
+                : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_ALLOW_AUDIO_PLAYBACK_CAPTURE;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setRequestLegacyExternalStorage(boolean requestLegacyExternalStorage) {
+        this.privateFlags = requestLegacyExternalStorage
+                ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_REQUEST_LEGACY_EXTERNAL_STORAGE
+                : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_REQUEST_LEGACY_EXTERNAL_STORAGE;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setUsesNonSdkApi(boolean usesNonSdkApi) {
+        this.privateFlags = usesNonSdkApi
+                ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_USES_NON_SDK_API
+                : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_USES_NON_SDK_API;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setHasFragileUserData(boolean hasFragileUserData) {
+        this.privateFlags = hasFragileUserData
+                ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_HAS_FRAGILE_USER_DATA
+                : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_HAS_FRAGILE_USER_DATA;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setCantSaveState(boolean cantSaveState) {
+        this.privateFlags = cantSaveState
+                ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE
+                : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE;
+        return this;
+    }
+
+    @Override
+    public boolean cantSaveState() {
+        return (privateFlags & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0;
+    }
+
+    @Override
+    public boolean isLibrary() {
+        return staticSharedLibName != null || !ArrayUtils.isEmpty(libraryNames);
+    }
+
+    // TODO(b/135203078): This does nothing until the final stage without applyPolicy being
+    //  part of PackageParser
+    @Override
+    public boolean isSystemApp() {
+        return (flags & ApplicationInfo.FLAG_SYSTEM) != 0;
+    }
+
+    // TODO(b/135203078): This does nothing until the final stage without applyPolicy being
+    //  part of PackageParser
+    @Override
+    public boolean isSystemExt() {
+        return (privateFlags & ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT) != 0;
+    }
+
+    // TODO(b/135203078): This does nothing until the final stage without applyPolicy being
+    //  part of PackageParser
+    @Override
+    public boolean isUpdatedSystemApp() {
+        return (flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0;
+    }
+
+    @Override
+    public PackageImpl setStaticSharedLibrary(boolean staticSharedLibrary) {
+        this.privateFlags = staticSharedLibrary
+                ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_STATIC_SHARED_LIBRARY
+                : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_STATIC_SHARED_LIBRARY;
+        return this;
+    }
+
+    @Override
+    public boolean isStaticSharedLibrary() {
+        return (privateFlags & ApplicationInfo.PRIVATE_FLAG_STATIC_SHARED_LIBRARY) != 0;
+    }
+
+    @Override
+    public PackageImpl setVisibleToInstantApps(boolean visibleToInstantApps) {
+        this.visibleToInstantApps = visibleToInstantApps;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setIconRes(int iconRes) {
+        this.iconRes = iconRes;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setRoundIconRes(int roundIconRes) {
+        this.roundIconRes = roundIconRes;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setClassName(String className) {
+        this.className = className;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setManageSpaceActivityName(String manageSpaceActivityName) {
+        this.manageSpaceActivityName = manageSpaceActivityName;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setBackupAgentName(String backupAgentName) {
+        this.backupAgentName = backupAgentName;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setFullBackupContent(int fullBackupContent) {
+        this.fullBackupContent = fullBackupContent;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setTheme(int theme) {
+        this.theme = theme;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setDescriptionRes(int descriptionRes) {
+        this.descriptionRes = descriptionRes;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setNetworkSecurityConfigRes(int networkSecurityConfigRes) {
+        this.networkSecurityConfigRes = networkSecurityConfigRes;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setCategory(int category) {
+        this.category = category;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setPermission(String permission) {
+        this.permission = permission;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setTaskAffinity(String taskAffinity) {
+        this.taskAffinity = taskAffinity;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setAppComponentFactory(String appComponentFactory) {
+        this.appComponentFactory = appComponentFactory;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setProcessName(String processName) {
+        if (processName == null) {
+            this.processName = packageName;
+        } else {
+            this.processName = processName;
+        }
+        return this;
+    }
+
+    @Override
+    public PackageImpl setEnabled(boolean enabled) {
+        this.enabled = enabled;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setUiOptions(int uiOptions) {
+        this.uiOptions = uiOptions;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setClassLoaderName(String classLoaderName) {
+        this.classLoaderName = classLoaderName;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setZygotePreloadName(String zygotePreloadName) {
+        this.zygotePreloadName = zygotePreloadName;
+        return this;
+    }
+
+    // parsePackageItemInfo
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public PackageImpl setName(String name) {
+        this.name = name;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setIcon(int icon) {
+        this.icon = icon;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setNonLocalizedLabel(CharSequence nonLocalizedLabel) {
+        this.nonLocalizedLabel = nonLocalizedLabel;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setLogo(int logo) {
+        this.logo = logo;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setBanner(int banner) {
+        this.banner = banner;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setLabelRes(int labelRes) {
+        this.labelRes = labelRes;
+        return this;
+    }
+
+    @Override
+    public PackageImpl asSplit(
+            String[] splitNames,
+            String[] splitCodePaths,
+            int[] splitRevisionCodes,
+            SparseArray<int[]> splitDependencies
+    ) {
+        this.splitNames = splitNames;
+
+        if (this.splitNames != null) {
+            for (int index = 0; index < this.splitNames.length; index++) {
+                splitNames[index] = TextUtils.safeIntern(splitNames[index]);
+            }
+        }
+
+        this.splitCodePaths = splitCodePaths;
+        this.splitRevisionCodes = splitRevisionCodes;
+        this.splitDependencies = splitDependencies;
+
+        int count = splitNames.length;
+        this.splitFlags = new int[count];
+        this.splitClassLoaderNames = new String[count];
+        return this;
+    }
+
+    @Override
+    public String[] getSplitNames() {
+        return splitNames;
+    }
+
+    @Override
+    public String[] getSplitCodePaths() {
+        return splitCodePaths;
+    }
+
+    @Override
+    public PackageImpl setSplitHasCode(int splitIndex, boolean splitHasCode) {
+        this.splitFlags[splitIndex] = splitHasCode
+                ? this.splitFlags[splitIndex] | ApplicationInfo.FLAG_HAS_CODE
+                : this.splitFlags[splitIndex] & ~ApplicationInfo.FLAG_HAS_CODE;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setSplitClassLoaderName(int splitIndex, String classLoaderName) {
+        this.splitClassLoaderNames[splitIndex] = classLoaderName;
+        return this;
+    }
+
+    @Override
+    public List<String> makeListAllCodePaths() {
+        ArrayList<String> paths = new ArrayList<>();
+        paths.add(baseCodePath);
+
+        if (!ArrayUtils.isEmpty(splitCodePaths)) {
+            Collections.addAll(paths, splitCodePaths);
+        }
+        return paths;
+    }
+
+    @Override
+    public PackageImpl setBaseCodePath(String baseCodePath) {
+        this.baseCodePath = baseCodePath;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setSplitCodePaths(String[] splitCodePaths) {
+        this.splitCodePaths = splitCodePaths;
+        return this;
+    }
+
+    @Override
+    public String toString() {
+        return "Package{"
+                + Integer.toHexString(System.identityHashCode(this))
+                + " " + packageName + "}";
+    }
+
+    @Override
+    public PackageImpl setPrimaryCpuAbi(String primaryCpuAbi) {
+        this.primaryCpuAbi = primaryCpuAbi;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setSecondaryCpuAbi(String secondaryCpuAbi) {
+        this.secondaryCpuAbi = secondaryCpuAbi;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setNativeLibraryRootDir(String nativeLibraryRootDir) {
+        this.nativeLibraryRootDir = nativeLibraryRootDir;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setNativeLibraryRootRequiresIsa(boolean nativeLibraryRootRequiresIsa) {
+        this.nativeLibraryRootRequiresIsa = nativeLibraryRootRequiresIsa;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setNativeLibraryDir(String nativeLibraryDir) {
+        this.nativeLibraryDir = nativeLibraryDir;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setSecondaryNativeLibraryDir(String secondaryNativeLibraryDir) {
+        this.secondaryNativeLibraryDir = secondaryNativeLibraryDir;
+        return this;
+    }
+
+    @Deprecated
+    @Override
+    public PackageImpl setApplicationInfoCodePath(String applicationInfoCodePath) {
+        this.applicationInfoCodePath = applicationInfoCodePath;
+        return this;
+    }
+
+    @Deprecated
+    @Override
+    public PackageImpl setApplicationInfoResourcePath(String applicationInfoResourcePath) {
+        this.applicationInfoResourcePath = applicationInfoResourcePath;
+        return this;
+    }
+
+    @Deprecated
+    @Override
+    public PackageImpl setApplicationInfoBaseResourcePath(
+            String applicationInfoBaseResourcePath) {
+        this.applicationInfoBaseResourcePath = applicationInfoBaseResourcePath;
+        return this;
+    }
+
+    @Deprecated
+    @Override
+    public PackageImpl setApplicationInfoSplitResourcePaths(
+            String[] applicationInfoSplitResourcePaths) {
+        this.applicationInfoSplitResourcePaths = applicationInfoSplitResourcePaths;
+        return this;
+    }
+
+    @Override
+    public boolean isDirectBootAware() {
+        return (privateFlags & ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE) != 0;
+    }
+
+    @Override
+    public PackageImpl setAllComponentsDirectBootAware(boolean allComponentsDirectBootAware) {
+        if (activities != null) {
+            for (ParsedActivity parsedActivity : activities) {
+                parsedActivity.directBootAware = allComponentsDirectBootAware;
+            }
+        }
+
+        if (receivers != null) {
+            for (ParsedActivity parsedReceiver : receivers) {
+                parsedReceiver.directBootAware = allComponentsDirectBootAware;
+            }
+        }
+
+        if (providers != null) {
+            for (ParsedProvider parsedProvider : providers) {
+                parsedProvider.directBootAware = allComponentsDirectBootAware;
+            }
+        }
+
+        if (services != null) {
+            for (ParsedService parsedService : services) {
+                parsedService.directBootAware = allComponentsDirectBootAware;
+            }
+        }
+
+        return this;
+    }
+
+    @Override
+    public PackageImpl setSystem(boolean system) {
+        this.flags = system
+                ? this.flags | ApplicationInfo.FLAG_SYSTEM
+                : this.flags & ~ApplicationInfo.FLAG_SYSTEM;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setSystemExt(boolean systemExt) {
+        this.privateFlags = systemExt
+                ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT
+                : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setIsStub(boolean isStub) {
+        this.isStub = isStub;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setCoreApp(boolean coreApp) {
+        this.coreApp = coreApp;
+        return this;
+    }
+
+    @Override
+    public ParsedPackage capPermissionPriorities() {
+        if (permissionGroups != null && !permissionGroups.isEmpty()) {
+            for (int i = permissionGroups.size() - 1; i >= 0; --i) {
+                // TODO(b/135203078): Builder/immutability
+                permissionGroups.get(i).priority = 0;
+            }
+        }
+        return this;
+    }
+
+    @Override
+    public ParsedPackage clearProtectedBroadcasts() {
+        if (protectedBroadcasts != null) {
+            protectedBroadcasts.clear();
+        }
+        return this;
+    }
+
+    @Override
+    public ParsedPackage markNotActivitiesAsNotExportedIfSingleUser() {
+        // ignore export request for single user receivers
+        if (receivers != null) {
+            for (ParsedActivity receiver : receivers) {
+                if ((receiver.flags & ActivityInfo.FLAG_SINGLE_USER) != 0) {
+                    receiver.exported = false;
+                }
+            }
+        }
+        // ignore export request for single user services
+        if (services != null) {
+            for (ParsedService service : services) {
+                if ((service.flags & ServiceInfo.FLAG_SINGLE_USER) != 0) {
+                    service.exported = false;
+                }
+            }
+        }
+        // ignore export request for single user providers
+        if (providers != null) {
+            for (ParsedProvider provider : providers) {
+                if ((provider.flags & ProviderInfo.FLAG_SINGLE_USER) != 0) {
+                    provider.exported = false;
+                }
+            }
+        }
+
+        return this;
+    }
+
+    @Override
+    public ParsedPackage setPrivileged(boolean privileged) {
+        this.privateFlags = privileged
+                ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_PRIVILEGED
+                : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
+        return this;
+    }
+
+    @Override
+    public ParsedPackage setOem(boolean oem) {
+        this.privateFlags = oem
+                ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_OEM
+                : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_OEM;
+        return this;
+    }
+
+    @Override
+    public ParsedPackage setVendor(boolean vendor) {
+        this.privateFlags = vendor
+                ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_VENDOR
+                : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_VENDOR;
+        return this;
+    }
+
+    @Override
+    public ParsedPackage setProduct(boolean product) {
+        this.privateFlags = product
+                ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_PRODUCT
+                : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_PRODUCT;
+        return this;
+    }
+
+    @Override
+    public ParsedPackage setOdm(boolean odm) {
+        this.privateFlags = odm
+                ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_ODM
+                : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_ODM;
+        return this;
+    }
+
+    @Override
+    public ParsedPackage setSignedWithPlatformKey(boolean signedWithPlatformKey) {
+        this.privateFlags = signedWithPlatformKey
+                ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_SIGNED_WITH_PLATFORM_KEY
+                : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_SIGNED_WITH_PLATFORM_KEY;
+        return this;
+    }
+
+    @Override
+    public ParsedPackage clearOriginalPackages() {
+        if (originalPackages != null) {
+            originalPackages.clear();
+        }
+        return this;
+    }
+
+    @Override
+    public ParsedPackage clearAdoptPermissions() {
+        if (adoptPermissions != null) {
+            adoptPermissions.clear();
+        }
+        return this;
+    }
+
+    @Override
+    public PackageImpl addUsesLibrary(int index, String libraryName) {
+        this.usesLibraries = ArrayUtils.add(usesLibraries, index, libraryName);
+        return this;
+    }
+
+    @Override
+    public ParsedPackage removeUsesLibrary(String libraryName) {
+        this.usesLibraries = ArrayUtils.remove(this.usesLibraries, libraryName);
+        return this;
+    }
+
+    @Override
+    public PackageImpl addUsesOptionalLibrary(int index, String libraryName) {
+        this.usesOptionalLibraries = ArrayUtils.add(usesOptionalLibraries, index, libraryName);
+        return this;
+    }
+
+    @Nullable
+    @Override
+    public List<String> getUsesOptionalLibraries() {
+        return usesOptionalLibraries;
+    }
+
+    @Override
+    public int getVersionCode() {
+        return versionCode;
+    }
+
+    @Nullable
+    @Override
+    public long[] getUsesStaticLibrariesVersions() {
+        return usesStaticLibrariesVersions;
+    }
+
+    @Override
+    public PackageImpl setPackageSettingCallback(PackageSettingCallback packageSettingCallback) {
+        packageSettingCallback.setAndroidPackage(this);
+        return this;
+    }
+
+    @Override
+    public PackageImpl setUpdatedSystemApp(boolean updatedSystemApp) {
+        this.flags = updatedSystemApp
+                ? this.flags | ApplicationInfo.FLAG_UPDATED_SYSTEM_APP
+                : this.flags & ~ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
+        return this;
+    }
+
+    @Override
+    public boolean isPrivileged() {
+        return (privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
+    }
+
+    @Override
+    public PackageImpl setSeInfo(String seInfo) {
+        this.seInfo = seInfo;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setSeInfoUser(String seInfoUser) {
+        this.seInfoUser = seInfoUser;
+        return this;
+    }
+
+    @Override
+    public PackageImpl initForUser(int userId) {
+        // TODO(b/135203078): Move this user state to some other data structure
+        this.uid = UserHandle.getUid(userId, UserHandle.getAppId(this.uid));
+
+        if ("android".equals(packageName)) {
+            dataDir = Environment.getDataSystemDirectory().getAbsolutePath();
+            return this;
+        }
+
+        deviceProtectedDataDir = Environment
+                .getDataUserDePackageDirectory(applicationVolumeUuid, userId, packageName)
+                .getAbsolutePath();
+        credentialProtectedDataDir = Environment
+                .getDataUserCePackageDirectory(applicationVolumeUuid, userId, packageName)
+                .getAbsolutePath();
+
+        if ((privateFlags & ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE) != 0
+                && PackageManager.APPLY_DEFAULT_TO_DEVICE_PROTECTED_STORAGE) {
+            dataDir = deviceProtectedDataDir;
+        } else {
+            dataDir = credentialProtectedDataDir;
+        }
+        return this;
+    }
+
+    @Override
+    public ParsedPackage setFactoryTest(boolean factoryTest) {
+        this.flags = factoryTest
+                ? this.flags | ApplicationInfo.FLAG_FACTORY_TEST
+                : this.flags & ~ApplicationInfo.FLAG_FACTORY_TEST;
+        return this;
+    }
+
+    @Override
+    public String getManifestPackageName() {
+        return manifestPackageName;
+    }
+
+    @Override
+    public String getRealPackage() {
+        return realPackage;
+    }
+
+    @Override
+    public String getOverlayTarget() {
+        return overlayTarget;
+    }
+
+    @Override
+    public String getOverlayTargetName() {
+        return overlayTargetName;
+    }
+
+    @Override
+    public boolean isOverlayIsStatic() {
+        return overlayIsStatic;
+    }
+
+    @Override
+    public int[] getSplitFlags() {
+        return splitFlags;
+    }
+
+    @Deprecated
+    @Override
+    public String getApplicationInfoVolumeUuid() {
+        return applicationVolumeUuid;
+    }
+
+    @Nullable
+    @Override
+    public List<String> getProtectedBroadcasts() {
+        return protectedBroadcasts;
+    }
+
+    @Nullable
+    @Override
+    public Set<String> getUpgradeKeySets() {
+        return upgradeKeySets;
+    }
+
+    @Nullable
+    @Override
+    public String[][] getUsesStaticLibrariesCertDigests() {
+        return usesStaticLibrariesCertDigests;
+    }
+
+    @Override
+    public int getOverlayPriority() {
+        return overlayPriority;
+    }
+
+    @Deprecated
+    @Override
+    public String getAppInfoPackageName() {
+        return packageName;
+    }
+
+    @Override
+    public UUID getStorageUuid() {
+        return StorageManager.convert(applicationVolumeUuid);
+    }
+
+    @Override
+    public int getUid() {
+        return uid;
+    }
+
+    @Override
+    public boolean isStub() {
+        return isStub;
+    }
+
+    @Deprecated
+    @Override
+    public String getAppInfoCodePath() {
+        return applicationInfoCodePath;
+    }
+
+    @Override
+    public boolean isSystem() {
+        return (flags & ApplicationInfo.FLAG_SYSTEM) != 0;
+    }
+
+    @Override
+    public boolean isMatch(int flags) {
+        if ((flags & PackageManager.MATCH_SYSTEM_ONLY) != 0) {
+            return isSystem();
+        }
+        return true;
+    }
+
+    @Override
+    public boolean isVisibleToInstantApps() {
+        return visibleToInstantApps;
+    }
+
+    @Override
+    public PackageImpl setLastPackageUsageTimeInMills(int reason, long time) {
+        lastPackageUsageTimeInMills[reason] = time;
+        return this;
+    }
+
+    @Override
+    public List<SharedLibraryInfo> getUsesLibraryInfos() {
+        return usesLibraryInfos;
+    }
+
+    @NonNull
+    @Override
+    public List<String> getAllCodePaths() {
+        return makeListAllCodePaths();
+    }
+
+    @Nullable
+    @Override
+    public String[] getUsesLibraryFiles() {
+        return usesLibraryFiles;
+    }
+
+    @Override
+    public PackageImpl setUsesLibraryInfos(
+            @Nullable List<SharedLibraryInfo> usesLibraryInfos) {
+        this.usesLibraryInfos = usesLibraryInfos;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setUsesLibraryFiles(@Nullable String[] usesLibraryFiles) {
+        this.usesLibraryFiles = usesLibraryFiles;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setUid(int uid) {
+        this.uid = uid;
+        return this;
+    }
+
+    @Override
+    public List<String> getAdoptPermissions() {
+        return adoptPermissions;
+    }
+
+    @Override
+    public ApplicationInfo toAppInfo() {
+        updateFlags();
+
+        ApplicationInfo applicationInfo = new ApplicationInfo();
+        applicationInfo.packageName = packageName;
+        applicationInfo.flags = flags;
+        applicationInfo.privateFlags = privateFlags;
+        applicationInfo.sharedLibraryFiles = usesLibraryFiles;
+        applicationInfo.sharedLibraryInfos = usesLibraryInfos;
+
+        applicationInfo.appComponentFactory = appComponentFactory;
+        applicationInfo.backupAgentName = backupAgentName;
+        applicationInfo.banner = banner;
+        applicationInfo.category = category;
+        applicationInfo.classLoaderName = classLoaderName;
+        applicationInfo.className = className;
+        applicationInfo.compatibleWidthLimitDp = compatibleWidthLimitDp;
+        applicationInfo.credentialProtectedDataDir = credentialProtectedDataDir;
+        applicationInfo.dataDir = dataDir;
+        applicationInfo.descriptionRes = descriptionRes;
+        applicationInfo.deviceProtectedDataDir = deviceProtectedDataDir;
+        applicationInfo.enabled = enabled;
+        applicationInfo.fullBackupContent = fullBackupContent;
+        applicationInfo.icon = icon;
+        applicationInfo.iconRes = iconRes;
+        applicationInfo.installLocation = installLocation;
+        applicationInfo.labelRes = labelRes;
+        applicationInfo.largestWidthLimitDp = largestWidthLimitDp;
+        applicationInfo.logo = logo;
+        applicationInfo.manageSpaceActivityName = manageSpaceActivityName;
+        applicationInfo.maxAspectRatio = maxAspectRatio;
+        applicationInfo.minAspectRatio = minAspectRatio;
+        applicationInfo.minSdkVersion = minSdkVersion;
+        applicationInfo.name = name;
+        applicationInfo.nativeLibraryDir = nativeLibraryDir;
+        applicationInfo.nativeLibraryRootDir = nativeLibraryRootDir;
+        applicationInfo.nativeLibraryRootRequiresIsa = nativeLibraryRootRequiresIsa;
+        applicationInfo.networkSecurityConfigRes = networkSecurityConfigRes;
+        applicationInfo.nonLocalizedLabel = nonLocalizedLabel;
+        applicationInfo.permission = permission;
+        applicationInfo.primaryCpuAbi = primaryCpuAbi;
+        applicationInfo.processName = processName;
+        applicationInfo.requiresSmallestWidthDp = requiresSmallestWidthDp;
+        applicationInfo.roundIconRes = roundIconRes;
+        applicationInfo.secondaryCpuAbi = secondaryCpuAbi;
+        applicationInfo.secondaryNativeLibraryDir = secondaryNativeLibraryDir;
+        applicationInfo.seInfo = seInfo;
+        applicationInfo.seInfoUser = seInfoUser;
+        applicationInfo.splitClassLoaderNames = splitClassLoaderNames;
+        applicationInfo.splitDependencies = splitDependencies;
+        applicationInfo.splitNames = splitNames;
+        applicationInfo.storageUuid = StorageManager.convert(applicationVolumeUuid);
+        applicationInfo.targetSandboxVersion = targetSandboxVersion;
+        applicationInfo.targetSdkVersion = targetSdkVersion;
+        applicationInfo.taskAffinity = taskAffinity;
+        applicationInfo.theme = theme;
+        applicationInfo.uid = uid;
+        applicationInfo.uiOptions = uiOptions;
+        applicationInfo.volumeUuid = applicationVolumeUuid;
+        applicationInfo.zygotePreloadName = zygotePreloadName;
+
+        applicationInfo.setBaseCodePath(baseCodePath);
+        applicationInfo.setBaseResourcePath(applicationInfoBaseResourcePath);
+        applicationInfo.setCodePath(applicationInfoCodePath);
+        applicationInfo.setResourcePath(applicationInfoResourcePath);
+        applicationInfo.setSplitCodePaths(splitCodePaths);
+        applicationInfo.setSplitResourcePaths(applicationInfoSplitResourcePaths);
+
+        return applicationInfo;
+    }
+
+    @Override
+    public PackageImpl setVersionCode(int versionCode) {
+        this.versionCode = versionCode;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setHiddenUntilInstalled(boolean hidden) {
+        this.hiddenUntilInstalled = hidden;
+        return this;
+    }
+
+    @Override
+    public String getSeInfo() {
+        return seInfo;
+    }
+
+    @Deprecated
+    @Override
+    public String getAppInfoResourcePath() {
+        return applicationInfoResourcePath;
+    }
+
+    @Override
+    public boolean isForwardLocked() {
+        // TODO(b/135203078): Unused? Move to debug flag?
+        return false;
+    }
+
+    @Override
+    public byte[] getRestrictUpdateHash() {
+        return restrictUpdateHash;
+    }
+
+    @Override
+    public boolean hasComponentClassName(String className) {
+        if (activities != null) {
+            for (ParsedActivity parsedActivity : activities) {
+                if (Objects.equals(className, parsedActivity.className)) {
+                    return true;
+                }
+            }
+        }
+
+        if (receivers != null) {
+            for (ParsedActivity receiver : receivers) {
+                if (Objects.equals(className, receiver.className)) {
+                    return true;
+                }
+            }
+        }
+
+        if (providers != null) {
+            for (ParsedProvider provider : providers) {
+                if (Objects.equals(className, provider.className)) {
+                    return true;
+                }
+            }
+        }
+
+        if (services != null) {
+            for (ParsedService service : services) {
+                if (Objects.equals(className, service.className)) {
+                    return true;
+                }
+            }
+        }
+
+        if (instrumentations != null) {
+            for (ParsedInstrumentation instrumentation : instrumentations) {
+                if (Objects.equals(className, instrumentation.className)) {
+                    return true;
+                }
+            }
+        }
+
+        return false;
+    }
+
+    @Override
+    public boolean isDefaultToDeviceProtectedStorage() {
+        return (privateFlags & ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE)
+                != 0;
+    }
+
+    @Override
+    public boolean isInternal() {
+        return (flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) == 0;
+    }
+
+    @Override
+    public int getBaseRevisionCode() {
+        return baseRevisionCode;
+    }
+
+    @Override
+    public int[] getSplitRevisionCodes() {
+        return splitRevisionCodes;
+    }
+
+    @Override
+    public boolean canHaveOatDir() {
+        // The following app types CANNOT have oat directory
+        // - non-updated system apps
+        return !isSystem() || isUpdatedSystemApp();
+    }
+
+    @Override
+    public long getLatestPackageUseTimeInMills() {
+        long latestUse = 0L;
+        for (long use : lastPackageUsageTimeInMills) {
+            latestUse = Math.max(latestUse, use);
+        }
+        return latestUse;
+    }
+
+    @Override
+    public long getLatestForegroundPackageUseTimeInMills() {
+        int[] foregroundReasons = {
+                PackageManager.NOTIFY_PACKAGE_USE_ACTIVITY,
+                PackageManager.NOTIFY_PACKAGE_USE_FOREGROUND_SERVICE
+        };
+
+        long latestUse = 0L;
+        for (int reason : foregroundReasons) {
+            latestUse = Math.max(latestUse, lastPackageUsageTimeInMills[reason]);
+        }
+        return latestUse;
+    }
+
+    @Override
+    public boolean isCoreApp() {
+        return coreApp;
+    }
+
+    @Override
+    public String getVersionName() {
+        return versionName;
+    }
+
+    @Override
+    public PackageImpl setVersionCodeMajor(int versionCodeMajor) {
+        this.versionCodeMajor = versionCodeMajor;
+        return this;
+    }
+
+    @Override
+    public long[] getLastPackageUsageTimeInMills() {
+        return lastPackageUsageTimeInMills;
+    }
+
+    @Override
+    public String getDataDir() {
+        return dataDir;
+    }
+
+    @Override
+    public boolean isExternal() {
+        return (flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0;
+    }
+
+    @Override
+    public List<String> getImplicitPermissions() {
+        return implicitPermissions == null ? Collections.emptyList() : implicitPermissions;
+    }
+
+    /**
+     * TODO(b/135203078): Remove, ensure b/140256621 is fixed or irrelevant
+     * TODO(b/140256621): Remove after fixing instant app check
+     * @deprecated This method always returns false because there's no paired set method
+     */
+    @Deprecated
+    @Override
+    public boolean isInstantApp() {
+        return (privateFlags & ApplicationInfo.PRIVATE_FLAG_INSTANT) != 0;
+    }
+
+    @Override
+    public boolean hasRequestedLegacyExternalStorage() {
+        return (privateFlags & ApplicationInfo.PRIVATE_FLAG_REQUEST_LEGACY_EXTERNAL_STORAGE) != 0;
+    }
+
+    @Override
+    public boolean isVendor() {
+        return (privateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0;
+    }
+
+    @Override
+    public boolean isProduct() {
+        return (privateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT) != 0;
+    }
+
+    @Override
+    public boolean isOem() {
+        return (privateFlags & ApplicationInfo.PRIVATE_FLAG_OEM) != 0;
+    }
+
+    @Override
+    public boolean isEncryptionAware() {
+        boolean isPartiallyDirectBootAware =
+                (privateFlags & ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE) != 0;
+        return isDirectBootAware() || isPartiallyDirectBootAware;
+    }
+
+    @Override
+    public boolean isEmbeddedDexUsed() {
+        return (privateFlags & ApplicationInfo.PRIVATE_FLAG_USE_EMBEDDED_DEX) != 0;
+    }
+
+    @Deprecated
+    @Override
+    public String getAppInfoProcessName() {
+        return processName;
+    }
+
+    @Override
+    public List<String> getAllCodePathsExcludingResourceOnly() {
+        ArrayList<String> paths = new ArrayList<>();
+        if ((flags & ApplicationInfo.FLAG_HAS_CODE) != 0) {
+            paths.add(baseCodePath);
+        }
+        if (!ArrayUtils.isEmpty(splitCodePaths)) {
+            for (int i = 0; i < splitCodePaths.length; i++) {
+                if ((splitFlags[i] & ApplicationInfo.FLAG_HAS_CODE) != 0) {
+                    paths.add(splitCodePaths[i]);
+                }
+            }
+        }
+        return paths;
+    }
+
+    @Deprecated
+    @Override
+    public String getAppInfoName() {
+        return name;
+    }
+
+    private boolean isSignedWithPlatformKey() {
+        return (privateFlags & ApplicationInfo.PRIVATE_FLAG_SIGNED_WITH_PLATFORM_KEY) != 0;
+    }
+
+    private boolean usesNonSdkApi() {
+        return (privateFlags & ApplicationInfo.PRIVATE_FLAG_USES_NON_SDK_API) != 0;
+    }
+
+    private boolean isPackageWhitelistedForHiddenApis() {
+        return SystemConfig.getInstance().getHiddenApiWhitelistedApps().contains(packageName);
+    }
+
+    private boolean isAllowedToUseHiddenApis() {
+        if (isSignedWithPlatformKey()) {
+            return true;
+        } else if (isSystemApp() || isUpdatedSystemApp()) {
+            return usesNonSdkApi() || isPackageWhitelistedForHiddenApis();
+        } else {
+            return false;
+        }
+    }
+
+    @Override
+    public int getHiddenApiEnforcementPolicy() {
+        if (isAllowedToUseHiddenApis()) {
+            return ApplicationInfo.HIDDEN_API_ENFORCEMENT_DISABLED;
+        }
+
+        // TODO(b/135203078): Handle maybeUpdateHiddenApiEnforcementPolicy. Right now it's done
+        //  entirely through ApplicationInfo and shouldn't touch this specific class, but that
+        //  may not always hold true.
+//        if (mHiddenApiPolicy != ApplicationInfo.HIDDEN_API_ENFORCEMENT_DEFAULT) {
+//            return mHiddenApiPolicy;
+//        }
+        return ApplicationInfo.HIDDEN_API_ENFORCEMENT_ENABLED;
+    }
+
+    @Nullable
+    @Override
+    public SparseArray<int[]> getSplitDependencies() {
+        return splitDependencies;
+    }
+
+    @Override
+    public boolean requestsIsolatedSplitLoading() {
+        return (privateFlags & ApplicationInfo.PRIVATE_FLAG_ISOLATED_SPLIT_LOADING) != 0;
+    }
+
+    @Deprecated
+    @Override
+    public String getAppInfoClassLoaderName() {
+        return classLoaderName;
+    }
+
+    @Override
+    public String getClassLoaderName() {
+        return classLoaderName;
+    }
+
+    @Override
+    public String[] getSplitClassLoaderNames() {
+        return splitClassLoaderNames;
+    }
+
+    @Override
+    public String getOverlayCategory() {
+        return overlayCategory;
+    }
+
+    @Override
+    public boolean isProfileableByShell() {
+        return (privateFlags & ApplicationInfo.PRIVATE_FLAG_PROFILEABLE_BY_SHELL) != 0;
+    }
+
+    @Nullable
+    @Override
+    public List<ParsedActivityIntentInfo> getPreferredActivityFilters() {
+        return preferredActivityFilters;
+    }
+
+    @Override
+    public boolean isHiddenUntilInstalled() {
+        return hiddenUntilInstalled;
+    }
+
+    @Override
+    public int getMinSdkVersion() {
+        return minSdkVersion;
+    }
+
+    @Override
+    public String getRestrictedAccountType() {
+        return restrictedAccountType;
+    }
+
+    @Override
+    public String getRequiredAccountType() {
+        return requiredAccountType;
+    }
+
+    @Override
+    public int getInstallLocation() {
+        return installLocation;
+    }
+
+    @Override
+    public List<ParsedActivity> getReceivers() {
+        return receivers;
+    }
+
+    @Override
+    public List<ParsedService> getServices() {
+        return services;
+    }
+
+    @Override
+    public List<ParsedProvider> getProviders() {
+        return providers;
+    }
+
+    @Override
+    public int getSharedUserLabel() {
+        return sharedUserLabel;
+    }
+
+    @Override
+    public int getVersionCodeMajor() {
+        return versionCodeMajor;
+    }
+
+    @Override
+    public boolean isRequiredForAllUsers() {
+        return requiredForAllUsers;
+    }
+
+    @Override
+    public int getCompileSdkVersion() {
+        return compileSdkVersion;
+    }
+
+    @Override
+    public String getCompileSdkVersionCodeName() {
+        return compileSdkVersionCodename;
+    }
+
+    @Nullable
+    @Override
+    public List<ConfigurationInfo> getConfigPreferences() {
+        return configPreferences;
+    }
+
+    @Nullable
+    @Override
+    public List<FeatureInfo> getReqFeatures() {
+        return reqFeatures;
+    }
+
+    @Override
+    public List<FeatureGroupInfo> getFeatureGroups() {
+        return featureGroups;
+    }
+
+    @Override
+    public String getDeviceProtectedDataDir() {
+        return deviceProtectedDataDir;
+    }
+
+    @Override
+    public String getCredentialProtectedDataDir() {
+        return credentialProtectedDataDir;
+    }
+
+    @Override
+    public String getSeInfoUser() {
+        return seInfoUser;
+    }
+
+    @Override
+    public String getClassName() {
+        return className;
+    }
+
+    @Override
+    public int getTheme() {
+        return theme;
+    }
+
+    @Override
+    public int getRequiresSmallestWidthDp() {
+        return requiresSmallestWidthDp;
+    }
+
+    @Override
+    public int getCompatibleWidthLimitDp() {
+        return compatibleWidthLimitDp;
+    }
+
+    @Override
+    public int getLargestWidthLimitDp() {
+        return largestWidthLimitDp;
+    }
+
+    @Override
+    public String getScanSourceDir() {
+        return applicationInfoCodePath;
+    }
+
+    @Override
+    public String getScanPublicSourceDir() {
+        return applicationInfoResourcePath;
+    }
+
+    @Override
+    public String getPublicSourceDir() {
+        return applicationInfoBaseResourcePath;
+    }
+
+    @Override
+    public String[] getSplitPublicSourceDirs() {
+        return applicationInfoSplitResourcePaths;
+    }
+
+    @Override
+    public String getSecondaryNativeLibraryDir() {
+        return secondaryNativeLibraryDir;
+    }
+
+    @Override
+    public boolean isEnabled() {
+        return enabled;
+    }
+
+    @Override
+    public String getManageSpaceActivityName() {
+        return manageSpaceActivityName;
+    }
+
+    @Override
+    public int getDescriptionRes() {
+        return descriptionRes;
+    }
+
+    @Override
+    public String getBackupAgentName() {
+        return backupAgentName;
+    }
+
+    @Override
+    public int getFullBackupContent() {
+        return fullBackupContent;
+    }
+
+    @Override
+    public int getNetworkSecurityConfigRes() {
+        return networkSecurityConfigRes;
+    }
+
+    @Override
+    public int getCategory() {
+        return category;
+    }
+
+    @Override
+    public int getTargetSandboxVersion() {
+        return targetSandboxVersion;
+    }
+
+    @Override
+    public String getAppComponentFactory() {
+        return appComponentFactory;
+    }
+
+    @Override
+    public int getIconRes() {
+        return iconRes;
+    }
+
+    @Override
+    public int getRoundIconRes() {
+        return roundIconRes;
+    }
+
+    @Override
+    public String getZygotePreloadName() {
+        return zygotePreloadName;
+    }
+
+    @Override
+    public int getLabelRes() {
+        return labelRes;
+    }
+
+    @Override
+    public CharSequence getNonLocalizedLabel() {
+        return nonLocalizedLabel;
+    }
+
+    @Override
+    public int getIcon() {
+        return icon;
+    }
+
+    @Override
+    public int getBanner() {
+        return banner;
+    }
+
+    @Override
+    public int getLogo() {
+        return logo;
+    }
+
+    @Override
+    public Bundle getMetaData() {
+        return appMetaData;
+    }
+
+    @Override
+    @Nullable
+    public List<Intent> getQueriesIntents() {
+        return queriesIntents;
+    }
+
+    @Override
+    @Nullable
+    public List<String> getQueriesPackages() {
+        return queriesPackages;
+    }
+
+    private static void internStringArrayList(List<String> list) {
+        if (list != null) {
+            final int N = list.size();
+            for (int i = 0; i < N; ++i) {
+                list.set(i, list.get(i).intern());
+            }
+        }
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(this.supportsSmallScreens);
+        dest.writeInt(this.supportsNormalScreens);
+        dest.writeInt(this.supportsLargeScreens);
+        dest.writeInt(this.supportsXLargeScreens);
+        dest.writeInt(this.resizeable);
+        dest.writeInt(this.anyDensity);
+        dest.writeLongArray(this.lastPackageUsageTimeInMills);
+        dest.writeInt(this.versionCode);
+        dest.writeInt(this.versionCodeMajor);
+        dest.writeInt(this.baseRevisionCode);
+        dest.writeString(this.versionName);
+        dest.writeBoolean(this.coreApp);
+        dest.writeInt(this.compileSdkVersion);
+        dest.writeString(this.compileSdkVersionCodename);
+        dest.writeString(this.packageName);
+        dest.writeString(this.realPackage);
+        dest.writeString(this.manifestPackageName);
+        dest.writeString(this.baseCodePath);
+        dest.writeBoolean(this.requiredForAllUsers);
+        dest.writeString(this.restrictedAccountType);
+        dest.writeString(this.requiredAccountType);
+        dest.writeBoolean(this.baseHardwareAccelerated);
+        dest.writeString(this.overlayTarget);
+        dest.writeString(this.overlayTargetName);
+        dest.writeString(this.overlayCategory);
+        dest.writeInt(this.overlayPriority);
+        dest.writeBoolean(this.overlayIsStatic);
+        dest.writeString(this.staticSharedLibName);
+        dest.writeLong(this.staticSharedLibVersion);
+        dest.writeStringList(this.libraryNames);
+        dest.writeStringList(this.usesLibraries);
+        dest.writeStringList(this.usesOptionalLibraries);
+        dest.writeStringList(this.usesStaticLibraries);
+        dest.writeLongArray(this.usesStaticLibrariesVersions);
+
+        if (this.usesStaticLibrariesCertDigests == null) {
+            dest.writeInt(-1);
+        } else {
+            dest.writeInt(this.usesStaticLibrariesCertDigests.length);
+            for (int index = 0; index < this.usesStaticLibrariesCertDigests.length; index++) {
+                dest.writeStringArray(this.usesStaticLibrariesCertDigests[index]);
+            }
+        }
+
+        dest.writeString(this.sharedUserId);
+        dest.writeInt(this.sharedUserLabel);
+        dest.writeTypedList(this.configPreferences);
+        dest.writeTypedList(this.reqFeatures);
+        dest.writeTypedList(this.featureGroups);
+        dest.writeByteArray(this.restrictUpdateHash);
+        dest.writeStringList(this.originalPackages);
+        dest.writeStringList(this.adoptPermissions);
+        dest.writeStringList(this.requestedPermissions);
+        dest.writeStringList(this.implicitPermissions);
+        dest.writeArraySet(this.upgradeKeySets);
+        dest.writeMap(this.keySetMapping);
+        dest.writeStringList(this.protectedBroadcasts);
+        dest.writeTypedList(this.activities);
+        dest.writeTypedList(this.receivers);
+        dest.writeTypedList(this.services);
+        dest.writeTypedList(this.providers);
+        dest.writeTypedList(this.permissions);
+        dest.writeTypedList(this.permissionGroups);
+        dest.writeTypedList(this.instrumentations);
+        ParsedIntentInfo.writeIntentsList(this.preferredActivityFilters, dest, flags);
+        dest.writeBundle(this.appMetaData);
+        dest.writeString(this.volumeUuid);
+        dest.writeString(this.applicationVolumeUuid);
+        dest.writeParcelable(this.signingDetails, flags);
+        dest.writeString(this.codePath);
+        dest.writeBoolean(this.use32BitAbi);
+        dest.writeBoolean(this.visibleToInstantApps);
+        dest.writeString(this.cpuAbiOverride);
+        dest.writeBoolean(this.isStub);
+        dest.writeInt(this.preferredOrder);
+        dest.writeBoolean(this.forceQueryable);
+        dest.writeParcelableList(this.queriesIntents, flags);
+        dest.writeStringList(this.queriesPackages);
+        dest.writeString(this.applicationInfoBaseResourcePath);
+        dest.writeString(this.applicationInfoCodePath);
+        dest.writeString(this.applicationInfoResourcePath);
+        dest.writeStringArray(this.applicationInfoSplitResourcePaths);
+        dest.writeString(this.appComponentFactory);
+        dest.writeString(this.backupAgentName);
+        dest.writeInt(this.banner);
+        dest.writeInt(this.category);
+        dest.writeString(this.classLoaderName);
+        dest.writeString(this.className);
+        dest.writeInt(this.compatibleWidthLimitDp);
+        dest.writeString(this.credentialProtectedDataDir);
+        dest.writeString(this.dataDir);
+        dest.writeInt(this.descriptionRes);
+        dest.writeString(this.deviceProtectedDataDir);
+        dest.writeBoolean(this.enabled);
+        dest.writeInt(this.flags);
+        dest.writeInt(this.fullBackupContent);
+        dest.writeBoolean(this.hiddenUntilInstalled);
+        dest.writeInt(this.icon);
+        dest.writeInt(this.iconRes);
+        dest.writeInt(this.installLocation);
+        dest.writeInt(this.labelRes);
+        dest.writeInt(this.largestWidthLimitDp);
+        dest.writeInt(this.logo);
+        dest.writeString(this.manageSpaceActivityName);
+        dest.writeFloat(this.maxAspectRatio);
+        dest.writeFloat(this.minAspectRatio);
+        dest.writeInt(this.minSdkVersion);
+        dest.writeString(this.name);
+        dest.writeString(this.nativeLibraryDir);
+        dest.writeString(this.nativeLibraryRootDir);
+        dest.writeBoolean(this.nativeLibraryRootRequiresIsa);
+        dest.writeInt(this.networkSecurityConfigRes);
+        dest.writeCharSequence(this.nonLocalizedLabel);
+        dest.writeString(this.permission);
+        dest.writeString(this.primaryCpuAbi);
+        dest.writeInt(this.privateFlags);
+        dest.writeString(this.processName);
+        dest.writeInt(this.requiresSmallestWidthDp);
+        dest.writeInt(this.roundIconRes);
+        dest.writeString(this.secondaryCpuAbi);
+        dest.writeString(this.secondaryNativeLibraryDir);
+        dest.writeString(this.seInfo);
+        dest.writeString(this.seInfoUser);
+        dest.writeInt(this.targetSandboxVersion);
+        dest.writeInt(this.targetSdkVersion);
+        dest.writeString(this.taskAffinity);
+        dest.writeInt(this.theme);
+        dest.writeInt(this.uid);
+        dest.writeInt(this.uiOptions);
+        dest.writeStringArray(this.usesLibraryFiles);
+        dest.writeTypedList(this.usesLibraryInfos);
+        dest.writeString(this.zygotePreloadName);
+        dest.writeStringArray(this.splitClassLoaderNames);
+        dest.writeStringArray(this.splitCodePaths);
+        dest.writeSparseArray(this.splitDependencies);
+        dest.writeIntArray(this.splitFlags);
+        dest.writeStringArray(this.splitNames);
+        dest.writeIntArray(this.splitRevisionCodes);
+    }
+
+    public PackageImpl(Parcel in) {
+        // We use the boot classloader for all classes that we load.
+        final ClassLoader boot = Object.class.getClassLoader();
+        this.supportsSmallScreens = in.readInt();
+        this.supportsNormalScreens = in.readInt();
+        this.supportsLargeScreens = in.readInt();
+        this.supportsXLargeScreens = in.readInt();
+        this.resizeable = in.readInt();
+        this.anyDensity = in.readInt();
+        this.lastPackageUsageTimeInMills = in.createLongArray();
+        this.versionCode = in.readInt();
+        this.versionCodeMajor = in.readInt();
+        this.baseRevisionCode = in.readInt();
+        this.versionName = TextUtils.safeIntern(in.readString());
+        this.coreApp = in.readBoolean();
+        this.compileSdkVersion = in.readInt();
+        this.compileSdkVersionCodename = TextUtils.safeIntern(in.readString());
+        this.packageName = TextUtils.safeIntern(in.readString());
+        this.realPackage = in.readString();
+        this.manifestPackageName = in.readString();
+        this.baseCodePath = in.readString();
+        this.requiredForAllUsers = in.readBoolean();
+        this.restrictedAccountType = in.readString();
+        this.requiredAccountType = in.readString();
+        this.baseHardwareAccelerated = in.readBoolean();
+        this.overlayTarget = in.readString();
+        this.overlayTargetName = in.readString();
+        this.overlayCategory = in.readString();
+        this.overlayPriority = in.readInt();
+        this.overlayIsStatic = in.readBoolean();
+        this.staticSharedLibName = TextUtils.safeIntern(in.readString());
+        this.staticSharedLibVersion = in.readLong();
+        this.libraryNames = in.createStringArrayList();
+        internStringArrayList(this.libraryNames);
+        this.usesLibraries = in.createStringArrayList();
+        internStringArrayList(this.usesLibraries);
+        this.usesOptionalLibraries = in.createStringArrayList();
+        internStringArrayList(this.usesOptionalLibraries);
+        this.usesStaticLibraries = in.createStringArrayList();
+        internStringArrayList(usesStaticLibraries);
+        this.usesStaticLibrariesVersions = in.createLongArray();
+
+        int digestsSize = in.readInt();
+        if (digestsSize >= 0) {
+            this.usesStaticLibrariesCertDigests = new String[digestsSize][];
+            for (int index = 0; index < digestsSize; index++) {
+                this.usesStaticLibrariesCertDigests[index] = in.readStringArray();
+            }
+        }
+
+        this.sharedUserId = TextUtils.safeIntern(in.readString());
+        this.sharedUserLabel = in.readInt();
+        this.configPreferences = in.createTypedArrayList(ConfigurationInfo.CREATOR);
+        this.reqFeatures = in.createTypedArrayList(FeatureInfo.CREATOR);
+        this.featureGroups = in.createTypedArrayList(FeatureGroupInfo.CREATOR);
+        this.restrictUpdateHash = in.createByteArray();
+        this.originalPackages = in.createStringArrayList();
+        this.adoptPermissions = in.createStringArrayList();
+        this.requestedPermissions = in.createStringArrayList();
+        internStringArrayList(this.requestedPermissions);
+        this.implicitPermissions = in.createStringArrayList();
+        internStringArrayList(this.implicitPermissions);
+        this.upgradeKeySets = (ArraySet<String>) in.readArraySet(boot);
+        this.keySetMapping = in.readHashMap(boot);
+        this.protectedBroadcasts = in.createStringArrayList();
+        internStringArrayList(this.protectedBroadcasts);
+        this.activities = in.createTypedArrayList(ParsedActivity.CREATOR);
+        this.receivers = in.createTypedArrayList(ParsedActivity.CREATOR);
+        this.services = in.createTypedArrayList(ParsedService.CREATOR);
+        this.providers = in.createTypedArrayList(ParsedProvider.CREATOR);
+        this.permissions = in.createTypedArrayList(ParsedPermission.CREATOR);
+        this.permissionGroups = in.createTypedArrayList(ParsedPermissionGroup.CREATOR);
+        this.instrumentations = in.createTypedArrayList(ParsedInstrumentation.CREATOR);
+        this.preferredActivityFilters = ParsedIntentInfo.createIntentsList(in);
+        this.appMetaData = in.readBundle(boot);
+        this.volumeUuid = in.readString();
+        this.applicationVolumeUuid = in.readString();
+        this.signingDetails = in.readParcelable(boot);
+        this.codePath = in.readString();
+        this.use32BitAbi = in.readBoolean();
+        this.visibleToInstantApps = in.readBoolean();
+        this.cpuAbiOverride = in.readString();
+        this.isStub = in.readBoolean();
+        this.preferredOrder = in.readInt();
+        this.forceQueryable = in.readBoolean();
+        this.queriesIntents = in.createTypedArrayList(Intent.CREATOR);
+        this.queriesPackages = in.createStringArrayList();
+        internStringArrayList(this.queriesPackages);
+        this.applicationInfoBaseResourcePath = in.readString();
+        this.applicationInfoCodePath = in.readString();
+        this.applicationInfoResourcePath = in.readString();
+        this.applicationInfoSplitResourcePaths = in.createStringArray();
+        this.appComponentFactory = in.readString();
+        this.backupAgentName = in.readString();
+        this.banner = in.readInt();
+        this.category = in.readInt();
+        this.classLoaderName = in.readString();
+        this.className = in.readString();
+        this.compatibleWidthLimitDp = in.readInt();
+        this.credentialProtectedDataDir = in.readString();
+        this.dataDir = in.readString();
+        this.descriptionRes = in.readInt();
+        this.deviceProtectedDataDir = in.readString();
+        this.enabled = in.readBoolean();
+        this.flags = in.readInt();
+        this.fullBackupContent = in.readInt();
+        this.hiddenUntilInstalled = in.readBoolean();
+        this.icon = in.readInt();
+        this.iconRes = in.readInt();
+        this.installLocation = in.readInt();
+        this.labelRes = in.readInt();
+        this.largestWidthLimitDp = in.readInt();
+        this.logo = in.readInt();
+        this.manageSpaceActivityName = in.readString();
+        this.maxAspectRatio = in.readFloat();
+        this.minAspectRatio = in.readFloat();
+        this.minSdkVersion = in.readInt();
+        this.name = in.readString();
+        this.nativeLibraryDir = in.readString();
+        this.nativeLibraryRootDir = in.readString();
+        this.nativeLibraryRootRequiresIsa = in.readBoolean();
+        this.networkSecurityConfigRes = in.readInt();
+        this.nonLocalizedLabel = in.readCharSequence();
+        this.permission = TextUtils.safeIntern(in.readString());
+        this.primaryCpuAbi = in.readString();
+        this.privateFlags = in.readInt();
+        this.processName = in.readString();
+        this.requiresSmallestWidthDp = in.readInt();
+        this.roundIconRes = in.readInt();
+        this.secondaryCpuAbi = in.readString();
+        this.secondaryNativeLibraryDir = in.readString();
+        this.seInfo = in.readString();
+        this.seInfoUser = in.readString();
+        this.targetSandboxVersion = in.readInt();
+        this.targetSdkVersion = in.readInt();
+        this.taskAffinity = in.readString();
+        this.theme = in.readInt();
+        this.uid = in.readInt();
+        this.uiOptions = in.readInt();
+        this.usesLibraryFiles = in.createStringArray();
+        this.usesLibraryInfos = in.createTypedArrayList(SharedLibraryInfo.CREATOR);
+        this.zygotePreloadName = in.readString();
+        this.splitClassLoaderNames = in.createStringArray();
+        this.splitCodePaths = in.createStringArray();
+        this.splitDependencies = in.readSparseArray(boot);
+        this.splitFlags = in.createIntArray();
+        this.splitNames = in.createStringArray();
+        this.splitRevisionCodes = in.createIntArray();
+    }
+
+    public static final Creator<PackageImpl> CREATOR = new Creator<PackageImpl>() {
+        @Override
+        public PackageImpl createFromParcel(Parcel source) {
+            return new PackageImpl(source);
+        }
+
+        @Override
+        public PackageImpl[] newArray(int size) {
+            return new PackageImpl[size];
+        }
+    };
+}
diff --git a/core/java/android/content/pm/parsing/PackageInfoUtils.java b/core/java/android/content/pm/parsing/PackageInfoUtils.java
new file mode 100644
index 0000000..7b329eb
--- /dev/null
+++ b/core/java/android/content/pm/parsing/PackageInfoUtils.java
@@ -0,0 +1,732 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm.parsing;
+
+import static android.content.pm.ApplicationInfo.FLAG_SUSPENDED;
+
+import android.annotation.Nullable;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.ComponentInfo;
+import android.content.pm.ConfigurationInfo;
+import android.content.pm.FallbackCategoryProvider;
+import android.content.pm.FeatureGroupInfo;
+import android.content.pm.FeatureInfo;
+import android.content.pm.InstrumentationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageItemInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageParser;
+import android.content.pm.PackageUserState;
+import android.content.pm.PermissionGroupInfo;
+import android.content.pm.PermissionInfo;
+import android.content.pm.ProviderInfo;
+import android.content.pm.SELinuxUtil;
+import android.content.pm.ServiceInfo;
+import android.content.pm.Signature;
+import android.content.pm.SigningInfo;
+import android.content.pm.parsing.ComponentParseUtils.ParsedActivity;
+import android.content.pm.parsing.ComponentParseUtils.ParsedInstrumentation;
+import android.content.pm.parsing.ComponentParseUtils.ParsedPermission;
+import android.content.pm.parsing.ComponentParseUtils.ParsedPermissionGroup;
+import android.os.Bundle;
+import android.os.UserHandle;
+
+import com.android.internal.util.ArrayUtils;
+
+import java.util.Set;
+
+/** @hide */
+public class PackageInfoUtils {
+
+    private static final String TAG = ApkParseUtils.TAG;
+
+    /**
+     * Returns true if the package is installed and not hidden, or if the caller
+     * explicitly wanted all uninstalled and hidden packages as well.
+     */
+    private static boolean checkUseInstalledOrHidden(AndroidPackage pkg, PackageUserState state,
+            @PackageManager.PackageInfoFlags int flags) {
+        // Returns false if the package is hidden system app until installed.
+        if ((flags & PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS) == 0
+                && !state.installed
+                && pkg.isHiddenUntilInstalled()) {
+            return false;
+        }
+
+        // If available for the target user, or trying to match uninstalled packages and it's
+        // a system app.
+        return state.isAvailable(flags)
+                || (pkg.isSystemApp()
+                && ((flags & PackageManager.MATCH_KNOWN_PACKAGES) != 0
+                || (flags & PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS) != 0));
+    }
+
+    public static PackageInfo generate(AndroidPackage pkg, int[] gids,
+            @PackageManager.PackageInfoFlags int flags, long firstInstallTime, long lastUpdateTime,
+            Set<String> grantedPermissions, PackageUserState state, int userId) {
+        if (!checkUseInstalledOrHidden(pkg, state, flags) || !pkg.isMatch(flags)) {
+            return null;
+        }
+        ApplicationInfo applicationInfo = generateApplicationInfo(pkg, flags, state, userId);
+
+        PackageInfo pi = new PackageInfo();
+        pi.packageName = pkg.getPackageName();
+        pi.splitNames = pkg.getSplitNames();
+        pi.versionCode = pkg.getVersionCode();
+        pi.versionCodeMajor = pkg.getVersionCodeMajor();
+        pi.baseRevisionCode = pkg.getBaseRevisionCode();
+        pi.splitRevisionCodes = pkg.getSplitRevisionCodes();
+        pi.versionName = pkg.getVersionName();
+        pi.sharedUserId = pkg.getSharedUserId();
+        pi.sharedUserLabel = pkg.getSharedUserLabel();
+        pi.applicationInfo = applicationInfo;
+        pi.installLocation = pkg.getInstallLocation();
+        pi.isStub = pkg.isStub();
+        pi.coreApp = pkg.isCoreApp();
+        if ((pi.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0
+                || (pi.applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
+            pi.requiredForAllUsers = pkg.isRequiredForAllUsers();
+        }
+        pi.restrictedAccountType = pkg.getRestrictedAccountType();
+        pi.requiredAccountType = pkg.getRequiredAccountType();
+        pi.overlayTarget = pkg.getOverlayTarget();
+        pi.targetOverlayableName = pkg.getOverlayTargetName();
+        pi.overlayCategory = pkg.getOverlayCategory();
+        pi.overlayPriority = pkg.getOverlayPriority();
+        pi.mOverlayIsStatic = pkg.isOverlayIsStatic();
+        pi.compileSdkVersion = pkg.getCompileSdkVersion();
+        pi.compileSdkVersionCodename = pkg.getCompileSdkVersionCodeName();
+        pi.firstInstallTime = firstInstallTime;
+        pi.lastUpdateTime = lastUpdateTime;
+        if ((flags & PackageManager.GET_GIDS) != 0) {
+            pi.gids = gids;
+        }
+        if ((flags & PackageManager.GET_CONFIGURATIONS) != 0) {
+            int size = pkg.getConfigPreferences() != null ? pkg.getConfigPreferences().size() : 0;
+            if (size > 0) {
+                pi.configPreferences = new ConfigurationInfo[size];
+                pkg.getConfigPreferences().toArray(pi.configPreferences);
+            }
+            size = pkg.getReqFeatures() != null ? pkg.getReqFeatures().size() : 0;
+            if (size > 0) {
+                pi.reqFeatures = new FeatureInfo[size];
+                pkg.getReqFeatures().toArray(pi.reqFeatures);
+            }
+            size = pkg.getFeatureGroups() != null ? pkg.getFeatureGroups().size() : 0;
+            if (size > 0) {
+                pi.featureGroups = new FeatureGroupInfo[size];
+                pkg.getFeatureGroups().toArray(pi.featureGroups);
+            }
+        }
+        if ((flags & PackageManager.GET_ACTIVITIES) != 0) {
+            if (pkg.getActivities() != null) {
+                final int N = pkg.getActivities().size();
+                if (N > 0) {
+                    int num = 0;
+                    final ActivityInfo[] res = new ActivityInfo[N];
+                    for (int i = 0; i < N; i++) {
+                        final ParsedActivity a = pkg.getActivities().get(i);
+                        if (state.isMatch(pkg.isSystem(), pkg.isEnabled(), a, flags)) {
+                            if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(
+                                    a.className)) {
+                                continue;
+                            }
+                            res[num++] = generateActivityInfo(pkg, a, flags, state, applicationInfo,
+                                    userId);
+                        }
+                    }
+                    pi.activities = ArrayUtils.trimToSize(res, num);
+                }
+            }
+        }
+        if ((flags & PackageManager.GET_RECEIVERS) != 0) {
+            if (pkg.getReceivers() != null) {
+                final int size = pkg.getReceivers().size();
+                if (size > 0) {
+                    int num = 0;
+                    final ActivityInfo[] res = new ActivityInfo[size];
+                    for (int i = 0; i < size; i++) {
+                        final ParsedActivity a = pkg.getReceivers().get(i);
+                        if (state.isMatch(pkg.isSystem(), pkg.isEnabled(), a, flags)) {
+                            res[num++] = generateActivityInfo(pkg, a, flags, state, applicationInfo,
+                                    userId);
+                        }
+                    }
+                    pi.receivers = ArrayUtils.trimToSize(res, num);
+                }
+            }
+        }
+        if ((flags & PackageManager.GET_SERVICES) != 0) {
+            if (pkg.getServices() != null) {
+                final int size = pkg.getServices().size();
+                if (size > 0) {
+                    int num = 0;
+                    final ServiceInfo[] res = new ServiceInfo[size];
+                    for (int i = 0; i < size; i++) {
+                        final ComponentParseUtils.ParsedService s = pkg.getServices().get(i);
+                        if (state.isMatch(pkg.isSystem(), pkg.isEnabled(), s, flags)) {
+                            res[num++] = generateServiceInfo(pkg, s, flags, state, applicationInfo,
+                                    userId);
+                        }
+                    }
+                    pi.services = ArrayUtils.trimToSize(res, num);
+                }
+            }
+        }
+        if ((flags & PackageManager.GET_PROVIDERS) != 0) {
+            if (pkg.getProviders() != null) {
+                final int size = pkg.getProviders().size();
+                if (size > 0) {
+                    int num = 0;
+                    final ProviderInfo[] res = new ProviderInfo[size];
+                    for (int i = 0; i < size; i++) {
+                        final ComponentParseUtils.ParsedProvider pr = pkg.getProviders()
+                                .get(i);
+                        if (state.isMatch(pkg.isSystem(), pkg.isEnabled(), pr, flags)) {
+                            res[num++] = generateProviderInfo(pkg, pr, flags, state,
+                                    applicationInfo, userId);
+                        }
+                    }
+                    pi.providers = ArrayUtils.trimToSize(res, num);
+                }
+            }
+        }
+        if ((flags & PackageManager.GET_INSTRUMENTATION) != 0) {
+            if (pkg.getInstrumentations() != null) {
+                int N = pkg.getInstrumentations().size();
+                if (N > 0) {
+                    pi.instrumentation = new InstrumentationInfo[N];
+                    for (int i = 0; i < N; i++) {
+                        pi.instrumentation[i] = generateInstrumentationInfo(
+                                pkg.getInstrumentations().get(i), flags);
+                    }
+                }
+            }
+        }
+        if ((flags & PackageManager.GET_PERMISSIONS) != 0) {
+            if (pkg.getPermissions() != null) {
+                int N = ArrayUtils.size(pkg.getPermissions());
+                if (N > 0) {
+                    pi.permissions = new PermissionInfo[N];
+                    for (int i = 0; i < N; i++) {
+                        pi.permissions[i] = generatePermissionInfo(
+                                pkg.getPermissions().get(i),
+                                flags
+                        );
+                    }
+                }
+            }
+            if (pkg.getRequestedPermissions() != null) {
+                int N = pkg.getRequestedPermissions().size();
+                if (N > 0) {
+                    pi.requestedPermissions = new String[N];
+                    pi.requestedPermissionsFlags = new int[N];
+                    for (int i = 0; i < N; i++) {
+                        final String perm = pkg.getRequestedPermissions().get(i);
+                        pi.requestedPermissions[i] = perm;
+                        // The notion of required permissions is deprecated but for compatibility.
+                        pi.requestedPermissionsFlags[i] |=
+                                PackageInfo.REQUESTED_PERMISSION_REQUIRED;
+                        if (grantedPermissions != null && grantedPermissions.contains(perm)) {
+                            pi.requestedPermissionsFlags[i] |=
+                                    PackageInfo.REQUESTED_PERMISSION_GRANTED;
+                        }
+                    }
+                }
+            }
+        }
+
+        PackageParser.SigningDetails signingDetails = pkg.getSigningDetails();
+        // deprecated method of getting signing certificates
+        if ((flags & PackageManager.GET_SIGNATURES) != 0) {
+            if (signingDetails.hasPastSigningCertificates()) {
+                // Package has included signing certificate rotation information.  Return the oldest
+                // cert so that programmatic checks keep working even if unaware of key rotation.
+                pi.signatures = new Signature[1];
+                pi.signatures[0] = signingDetails.pastSigningCertificates[0];
+            } else if (signingDetails.hasSignatures()) {
+                // otherwise keep old behavior
+                int numberOfSigs = signingDetails.signatures.length;
+                pi.signatures = new Signature[numberOfSigs];
+                System.arraycopy(signingDetails.signatures, 0, pi.signatures, 0,
+                        numberOfSigs);
+            }
+        }
+
+        // replacement for GET_SIGNATURES
+        if ((flags & PackageManager.GET_SIGNING_CERTIFICATES) != 0) {
+            if (signingDetails != PackageParser.SigningDetails.UNKNOWN) {
+                // only return a valid SigningInfo if there is signing information to report
+                pi.signingInfo = new SigningInfo(signingDetails);
+            } else {
+                pi.signingInfo = null;
+            }
+        }
+
+        return pi;
+    }
+
+    // TODO(b/135203078): Remove this in favor of AndroidPackage.toAppInfo()
+    private static ApplicationInfo appInfoFromFinalPackage(AndroidPackage pkg) {
+        ApplicationInfo appInfo = new ApplicationInfo();
+        appInfo.name = pkg.getName();
+        if (appInfo.name != null) appInfo.name = appInfo.name.trim();
+        appInfo.packageName = pkg.getPackageName();
+        appInfo.labelRes = pkg.getLabelRes();
+        appInfo.nonLocalizedLabel = pkg.getNonLocalizedLabel();
+        if (appInfo.nonLocalizedLabel != null) {
+            appInfo.nonLocalizedLabel = appInfo.nonLocalizedLabel.toString().trim();
+        }
+        appInfo.icon = pkg.getIcon();
+        appInfo.banner = pkg.getBanner();
+        appInfo.logo = pkg.getLogo();
+        appInfo.metaData = pkg.getMetaData();
+
+        // TODO(b/135203078): Can this be removed? Looks only used in ActivityInfo.
+//        appInfo.showUserIcon = pkg.getShowUserIcon();
+
+        appInfo.taskAffinity = pkg.getTaskAffinity();
+        appInfo.permission = pkg.getPermission();
+        appInfo.processName = pkg.getProcessName();
+        appInfo.className = pkg.getClassName();
+        appInfo.theme = pkg.getTheme();
+        appInfo.flags = pkg.getFlags();
+        appInfo.privateFlags = pkg.getPrivateFlags();
+        appInfo.requiresSmallestWidthDp = pkg.getRequiresSmallestWidthDp();
+        appInfo.compatibleWidthLimitDp = pkg.getCompatibleWidthLimitDp();
+        appInfo.largestWidthLimitDp = pkg.getLargestWidthLimitDp();
+        appInfo.volumeUuid = pkg.getVolumeUuid();
+        appInfo.storageUuid = pkg.getStorageUuid();
+        appInfo.scanSourceDir = pkg.getScanSourceDir();
+        appInfo.scanPublicSourceDir = pkg.getScanPublicSourceDir();
+        appInfo.sourceDir = pkg.getBaseCodePath();
+        appInfo.publicSourceDir = pkg.getPublicSourceDir();
+        appInfo.splitNames = pkg.getSplitNames();
+        appInfo.splitSourceDirs = pkg.getSplitCodePaths();
+        appInfo.splitPublicSourceDirs = pkg.getSplitPublicSourceDirs();
+        appInfo.splitDependencies = pkg.getSplitDependencies();
+        appInfo.nativeLibraryDir = pkg.getNativeLibraryDir();
+        appInfo.secondaryNativeLibraryDir = pkg.getSecondaryNativeLibraryDir();
+        appInfo.nativeLibraryRootDir = pkg.getNativeLibraryRootDir();
+        appInfo.nativeLibraryRootRequiresIsa = pkg.isNativeLibraryRootRequiresIsa();
+        appInfo.primaryCpuAbi = pkg.getPrimaryCpuAbi();
+        appInfo.secondaryCpuAbi = pkg.getSecondaryCpuAbi();
+
+        // TODO(b/135203078): Unused?
+//        appInfo.resourceDirs = pkg.getResourceDirs();
+        appInfo.seInfo = pkg.getSeInfo();
+        appInfo.seInfoUser = pkg.getSeInfoUser();
+        appInfo.sharedLibraryFiles = pkg.getUsesLibraryFiles();
+        appInfo.sharedLibraryInfos = pkg.getUsesLibraryInfos();
+        appInfo.dataDir = pkg.getDataDir();
+        appInfo.deviceProtectedDataDir = pkg.getDeviceProtectedDataDir();
+        appInfo.credentialProtectedDataDir = pkg.getCredentialProtectedDataDir();
+        appInfo.uid = pkg.getUid();
+        appInfo.minSdkVersion = pkg.getMinSdkVersion();
+        appInfo.targetSdkVersion = pkg.getTargetSdkVersion();
+        appInfo.setVersionCode(pkg.getLongVersionCode());
+        appInfo.enabled = pkg.isEnabled();
+
+        // TODO(b/135203078): Unused?
+//        appInfo.enabledSetting = pkg.getEnabledSetting();
+        appInfo.installLocation = pkg.getInstallLocation();
+        appInfo.manageSpaceActivityName = pkg.getManageSpaceActivityName();
+        appInfo.descriptionRes = pkg.getDescriptionRes();
+        appInfo.uiOptions = pkg.getUiOptions();
+        appInfo.backupAgentName = pkg.getBackupAgentName();
+        appInfo.fullBackupContent = pkg.getFullBackupContent();
+        appInfo.networkSecurityConfigRes = pkg.getNetworkSecurityConfigRes();
+        appInfo.category = pkg.getCategory();
+        appInfo.targetSandboxVersion = pkg.getTargetSandboxVersion();
+        appInfo.classLoaderName = pkg.getClassLoaderName();
+        appInfo.splitClassLoaderNames = pkg.getSplitClassLoaderNames();
+        appInfo.appComponentFactory = pkg.getAppComponentFactory();
+        appInfo.iconRes = pkg.getIconRes();
+        appInfo.roundIconRes = pkg.getRoundIconRes();
+        appInfo.compileSdkVersion = pkg.getCompileSdkVersion();
+        appInfo.compileSdkVersionCodename = pkg.getCompileSdkVersionCodeName();
+
+        // TODO(b/135203078): See PackageImpl#getHiddenApiEnforcementPolicy
+//        appInfo.mHiddenApiPolicy = pkg.getHiddenApiPolicy();
+        appInfo.hiddenUntilInstalled = pkg.isHiddenUntilInstalled();
+        appInfo.zygotePreloadName = pkg.getZygotePreloadName();
+        return appInfo;
+    }
+
+    public static ApplicationInfo generateApplicationInfo(AndroidPackage pkg,
+            @PackageManager.ApplicationInfoFlags int flags, PackageUserState state, int userId) {
+
+        if (pkg == null) return null;
+        if (!checkUseInstalledOrHidden(pkg, state, flags) || !pkg.isMatch(flags)) {
+            return null;
+        }
+        if (!copyNeeded(flags, pkg, state, null, userId)
+                && ((flags & PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS) == 0
+                || state.enabled != PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED)) {
+            // TODO(b/135203078): This isn't applicable anymore, as AppInfo isn't cached and
+            //   always built new in toAppInfo(). Remove entire copyNeeded flow? Or find a way to
+            //   transiently cache AppInfo, since multiple calls in quick secession probably need
+            //   the same AppInfo.
+            // In this case it is safe to directly modify the internal ApplicationInfo state:
+            // - CompatibilityMode is global state, so will be the same for every call.
+            // - We only come in to here if the app should reported as installed; this is the
+            // default state, and we will do a copy otherwise.
+            // - The enable state will always be reported the same for the application across
+            // calls; the only exception is for the UNTIL_USED mode, and in that case we will
+            // be doing a copy.
+            ApplicationInfo applicationInfo = pkg.toAppInfo();
+            updateApplicationInfo(applicationInfo, flags, state);
+            return applicationInfo;
+        }
+
+        // Make shallow copy so we can store the metadata/libraries safely
+        ApplicationInfo ai = appInfoFromFinalPackage(pkg);
+        ai.initForUser(userId);
+        if ((flags & PackageManager.GET_META_DATA) != 0) {
+            ai.metaData = pkg.getAppMetaData();
+        }
+        if ((flags & PackageManager.GET_SHARED_LIBRARY_FILES) != 0) {
+            ai.sharedLibraryFiles = pkg.getUsesLibraryFiles();
+            ai.sharedLibraryInfos = pkg.getUsesLibraryInfos();
+        }
+        if (state.stopped) {
+            ai.flags |= ApplicationInfo.FLAG_STOPPED;
+        } else {
+            ai.flags &= ~ApplicationInfo.FLAG_STOPPED;
+        }
+        updateApplicationInfo(ai, flags, state);
+
+        return ai;
+    }
+
+    private static ActivityInfo generateActivityInfo(AndroidPackage pkg, ParsedActivity a,
+            @PackageManager.ComponentInfoFlags int flags, PackageUserState state,
+            @Nullable ApplicationInfo applicationInfo, int userId) {
+        if (a == null) return null;
+        if (!checkUseInstalledOrHidden(pkg, state, flags)) {
+            return null;
+        }
+        if (applicationInfo == null) {
+            applicationInfo = generateApplicationInfo(pkg, flags, state, userId);
+        }
+        if (!copyNeeded(flags, pkg, state, a.metaData, userId)) {
+            updateApplicationInfo(applicationInfo, flags, state);
+        }
+        // Make shallow copies so we can store the metadata safely
+        ActivityInfo ai = new ActivityInfo();
+        assignSharedFieldsForComponentInfo(ai, a);
+        ai.targetActivity = a.targetActivity;
+        ai.processName = a.getProcessName();
+        ai.exported = a.exported;
+        ai.theme = a.theme;
+        ai.uiOptions = a.uiOptions;
+        ai.parentActivityName = a.parentActivityName;
+        ai.permission = a.getPermission();
+        ai.taskAffinity = a.taskAffinity;
+        ai.flags = a.flags;
+        ai.privateFlags = a.privateFlags;
+        ai.launchMode = a.launchMode;
+        ai.documentLaunchMode = a.documentLaunchMode;
+        ai.maxRecents = a.maxRecents;
+        ai.configChanges = a.configChanges;
+        ai.softInputMode = a.softInputMode;
+        ai.persistableMode = a.persistableMode;
+        ai.lockTaskLaunchMode = a.lockTaskLaunchMode;
+        ai.screenOrientation = a.screenOrientation;
+        ai.resizeMode = a.resizeMode;
+        ai.maxAspectRatio = a.maxAspectRatio;
+        ai.minAspectRatio = a.minAspectRatio;
+        ai.requestedVrComponent = a.requestedVrComponent;
+        ai.rotationAnimation = a.rotationAnimation;
+        ai.colorMode = a.colorMode;
+        ai.windowLayout = a.windowLayout;
+        ai.metaData = a.metaData;
+        ai.applicationInfo = applicationInfo;
+        return ai;
+    }
+
+    public static ActivityInfo generateActivityInfo(AndroidPackage pkg, ParsedActivity a,
+            @PackageManager.ComponentInfoFlags int flags, PackageUserState state, int userId) {
+        return generateActivityInfo(pkg, a, flags, state, null, userId);
+    }
+
+    private static ServiceInfo generateServiceInfo(AndroidPackage pkg,
+            ComponentParseUtils.ParsedService s, @PackageManager.ComponentInfoFlags int flags,
+            PackageUserState state, @Nullable ApplicationInfo applicationInfo, int userId) {
+        if (s == null) return null;
+        if (!checkUseInstalledOrHidden(pkg, state, flags)) {
+            return null;
+        }
+        if (applicationInfo == null) {
+            applicationInfo = generateApplicationInfo(pkg, flags, state, userId);
+        }
+        if (!copyNeeded(flags, pkg, state, s.metaData, userId)) {
+            updateApplicationInfo(applicationInfo, flags, state);
+        }
+        // Make shallow copies so we can store the metadata safely
+        ServiceInfo si = new ServiceInfo();
+        assignSharedFieldsForComponentInfo(si, s);
+        si.exported = s.exported;
+        si.flags = s.flags;
+        si.metaData = s.metaData;
+        si.permission = s.getPermission();
+        si.processName = s.getProcessName();
+        si.mForegroundServiceType = s.foregroundServiceType;
+        si.metaData = s.metaData;
+        si.applicationInfo = applicationInfo;
+        return si;
+    }
+
+    public static ServiceInfo generateServiceInfo(AndroidPackage pkg,
+            ComponentParseUtils.ParsedService s, @PackageManager.ComponentInfoFlags int flags,
+            PackageUserState state, int userId) {
+        return generateServiceInfo(pkg, s, flags, state, null, userId);
+    }
+
+    private static ProviderInfo generateProviderInfo(AndroidPackage pkg,
+            ComponentParseUtils.ParsedProvider p, @PackageManager.ComponentInfoFlags int flags,
+            PackageUserState state, @Nullable ApplicationInfo applicationInfo, int userId) {
+        if (p == null) return null;
+        if (!checkUseInstalledOrHidden(pkg, state, flags)) {
+            return null;
+        }
+        if (applicationInfo == null) {
+            applicationInfo = generateApplicationInfo(pkg, flags, state, userId);
+        }
+        if (!copyNeeded(flags, pkg, state, p.metaData, userId)
+                && ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) != 0
+                || p.uriPermissionPatterns == null)) {
+            updateApplicationInfo(applicationInfo, flags, state);
+        }
+        // Make shallow copies so we can store the metadata safely
+        ProviderInfo pi = new ProviderInfo();
+        assignSharedFieldsForComponentInfo(pi, p);
+        pi.exported = p.exported;
+        pi.flags = p.flags;
+        pi.processName = p.getProcessName();
+        pi.authority = p.getAuthority();
+        pi.isSyncable = p.isSyncable;
+        pi.readPermission = p.getReadPermission();
+        pi.writePermission = p.getWritePermission();
+        pi.grantUriPermissions = p.grantUriPermissions;
+        pi.forceUriPermissions = p.forceUriPermissions;
+        pi.multiprocess = p.multiProcess;
+        pi.initOrder = p.initOrder;
+        pi.uriPermissionPatterns = p.uriPermissionPatterns;
+        pi.pathPermissions = p.pathPermissions;
+        pi.metaData = p.metaData;
+        if ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) == 0) {
+            pi.uriPermissionPatterns = null;
+        }
+        pi.applicationInfo = applicationInfo;
+        return pi;
+    }
+
+    public static ProviderInfo generateProviderInfo(AndroidPackage pkg,
+            ComponentParseUtils.ParsedProvider p, @PackageManager.ComponentInfoFlags int flags,
+            PackageUserState state, int userId) {
+        return generateProviderInfo(pkg, p, flags, state, null, userId);
+    }
+
+    public static InstrumentationInfo generateInstrumentationInfo(ParsedInstrumentation i,
+            @PackageManager.ComponentInfoFlags int flags) {
+        if (i == null) return null;
+
+        InstrumentationInfo ii = new InstrumentationInfo();
+        assignSharedFieldsForPackageItemInfo(ii, i);
+        ii.targetPackage = i.getTargetPackage();
+        ii.targetProcesses = i.getTargetProcesses();
+        ii.handleProfiling = i.handleProfiling;
+        ii.functionalTest = i.functionalTest;
+
+        ii.sourceDir = i.sourceDir;
+        ii.publicSourceDir = i.publicSourceDir;
+        ii.splitNames = i.splitNames;
+        ii.splitSourceDirs = i.splitSourceDirs;
+        ii.splitPublicSourceDirs = i.splitPublicSourceDirs;
+        ii.splitDependencies = i.splitDependencies;
+        ii.dataDir = i.dataDir;
+        ii.deviceProtectedDataDir = i.deviceProtectedDataDir;
+        ii.credentialProtectedDataDir = i.credentialProtectedDataDir;
+        ii.primaryCpuAbi = i.primaryCpuAbi;
+        ii.secondaryCpuAbi = i.secondaryCpuAbi;
+        ii.nativeLibraryDir = i.nativeLibraryDir;
+        ii.secondaryNativeLibraryDir = i.secondaryNativeLibraryDir;
+
+        if ((flags & PackageManager.GET_META_DATA) == 0) {
+            return ii;
+        }
+        ii.metaData = i.metaData;
+        return ii;
+    }
+
+    public static PermissionInfo generatePermissionInfo(ParsedPermission p,
+            @PackageManager.ComponentInfoFlags int flags) {
+        if (p == null) return null;
+
+        PermissionInfo pi = new PermissionInfo(p.backgroundPermission);
+        assignSharedFieldsForPackageItemInfo(pi, p);
+        pi.group = p.getGroup();
+        pi.requestRes = p.requestRes;
+        pi.protectionLevel = p.protectionLevel;
+        pi.descriptionRes = p.descriptionRes;
+        pi.flags = p.flags;
+
+        if ((flags & PackageManager.GET_META_DATA) == 0) {
+            return pi;
+        }
+        pi.metaData = p.metaData;
+        return pi;
+    }
+
+    public static PermissionGroupInfo generatePermissionGroupInfo(ParsedPermissionGroup pg,
+            @PackageManager.ComponentInfoFlags int flags) {
+        if (pg == null) return null;
+
+        PermissionGroupInfo pgi = new PermissionGroupInfo(
+                pg.requestDetailResourceId,
+                pg.backgroundRequestResourceId,
+                pg.backgroundRequestDetailResourceId
+        );
+        assignSharedFieldsForPackageItemInfo(pgi, pg);
+        pgi.priority = pg.priority;
+        pgi.requestRes = pg.requestRes;
+        pgi.flags = pg.flags;
+
+        if ((flags & PackageManager.GET_META_DATA) == 0) {
+            return pgi;
+        }
+        pgi.metaData = pg.metaData;
+        return pgi;
+    }
+
+    private static boolean copyNeeded(@PackageManager.ComponentInfoFlags int flags,
+            AndroidPackage pkg, PackageUserState state, Bundle metaData, int userId) {
+        if (userId != UserHandle.USER_SYSTEM) {
+            // We always need to copy for other users, since we need
+            // to fix up the uid.
+            return true;
+        }
+        if (state.enabled != PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
+            boolean enabled = state.enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
+            if (pkg.isEnabled() != enabled) {
+                return true;
+            }
+        }
+        boolean suspended = (pkg.getFlags() & FLAG_SUSPENDED) != 0;
+        if (state.suspended != suspended) {
+            return true;
+        }
+        if (!state.installed || state.hidden) {
+            return true;
+        }
+        if (state.stopped) {
+            return true;
+        }
+        if (state.instantApp != pkg.isInstantApp()) {
+            return true;
+        }
+        if ((flags & PackageManager.GET_META_DATA) != 0
+                && (metaData != null || pkg.getAppMetaData() != null)) {
+            return true;
+        }
+        if ((flags & PackageManager.GET_SHARED_LIBRARY_FILES) != 0
+                && pkg.getUsesLibraryFiles() != null) {
+            return true;
+        }
+        if ((flags & PackageManager.GET_SHARED_LIBRARY_FILES) != 0
+                && pkg.getUsesLibraryInfos() != null) {
+            return true;
+        }
+        return pkg.getStaticSharedLibName() != null;
+    }
+
+    private static void updateApplicationInfo(ApplicationInfo ai,
+            @PackageManager.ApplicationInfoFlags int flags,
+            PackageUserState state) {
+        // CompatibilityMode is global state.
+        if (!PackageParser.sCompatibilityModeEnabled) {
+            ai.disableCompatibilityMode();
+        }
+        if (state.installed) {
+            ai.flags |= ApplicationInfo.FLAG_INSTALLED;
+        } else {
+            ai.flags &= ~ApplicationInfo.FLAG_INSTALLED;
+        }
+        if (state.suspended) {
+            ai.flags |= ApplicationInfo.FLAG_SUSPENDED;
+        } else {
+            ai.flags &= ~ApplicationInfo.FLAG_SUSPENDED;
+        }
+        if (state.instantApp) {
+            ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_INSTANT;
+        } else {
+            ai.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_INSTANT;
+        }
+        if (state.virtualPreload) {
+            ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_VIRTUAL_PRELOAD;
+        } else {
+            ai.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_VIRTUAL_PRELOAD;
+        }
+        if (state.hidden) {
+            ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_HIDDEN;
+        } else {
+            ai.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_HIDDEN;
+        }
+        if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
+            ai.enabled = true;
+        } else if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
+            ai.enabled = (flags & PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS) != 0;
+        } else if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED
+                || state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) {
+            ai.enabled = false;
+        }
+        ai.enabledSetting = state.enabled;
+        if (ai.category == ApplicationInfo.CATEGORY_UNDEFINED) {
+            ai.category = state.categoryHint;
+        }
+        if (ai.category == ApplicationInfo.CATEGORY_UNDEFINED) {
+            ai.category = FallbackCategoryProvider.getFallbackCategory(ai.packageName);
+        }
+        ai.seInfoUser = SELinuxUtil.assignSeinfoUser(state);
+        ai.resourceDirs = state.overlayPaths;
+        ai.icon = (PackageParser.sUseRoundIcon && ai.roundIconRes != 0)
+                ? ai.roundIconRes : ai.iconRes;
+    }
+
+    private static void assignSharedFieldsForPackageItemInfo(PackageItemInfo packageItemInfo,
+            ComponentParseUtils.ParsedComponent parsedComponent) {
+        packageItemInfo.banner = parsedComponent.banner;
+        packageItemInfo.icon = parsedComponent.icon;
+        packageItemInfo.labelRes = parsedComponent.labelRes;
+        packageItemInfo.logo = parsedComponent.logo;
+        packageItemInfo.name = parsedComponent.className;
+        packageItemInfo.nonLocalizedLabel = parsedComponent.nonLocalizedLabel;
+        packageItemInfo.packageName = parsedComponent.getPackageName();
+    }
+
+    private static void assignSharedFieldsForComponentInfo(ComponentInfo componentInfo,
+            ComponentParseUtils.ParsedComponent parsedComponent) {
+        assignSharedFieldsForPackageItemInfo(componentInfo, parsedComponent);
+        componentInfo.descriptionRes = parsedComponent.descriptionRes;
+        componentInfo.directBootAware = parsedComponent.directBootAware;
+        componentInfo.enabled = parsedComponent.enabled;
+        componentInfo.splitName = parsedComponent.getSplitName();
+    }
+
+}
diff --git a/core/java/android/content/pm/parsing/ParsedPackage.java b/core/java/android/content/pm/parsing/ParsedPackage.java
new file mode 100644
index 0000000..05cf586
--- /dev/null
+++ b/core/java/android/content/pm/parsing/ParsedPackage.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm.parsing;
+
+import android.content.pm.PackageParser;
+
+/**
+ * Methods used for mutation after direct package parsing, mostly done inside
+ * {@link com.android.server.pm.PackageManagerService}.
+ *
+ * Java disallows defining this as an inner interface, so this must be a separate file.
+ *
+ * @hide
+ */
+public interface ParsedPackage extends AndroidPackage {
+
+    AndroidPackage hideAsFinal();
+
+    ParsedPackage addUsesLibrary(int index, String libraryName);
+
+    ParsedPackage addUsesOptionalLibrary(int index, String libraryName);
+
+    ParsedPackage capPermissionPriorities();
+
+    ParsedPackage clearAdoptPermissions();
+
+    ParsedPackage clearOriginalPackages();
+
+    ParsedPackage clearProtectedBroadcasts();
+
+    /**
+     * TODO(b/135203078): Use non-AppInfo method
+     * @deprecated use {@link #setCodePath(String)}
+     */
+    @Deprecated
+    ParsedPackage setApplicationInfoCodePath(String applicationInfoCodePath);
+
+    /**
+     * TODO(b/135203078): Use non-AppInfo method
+     * @deprecated use {@link #setCodePath(String)}
+     */
+    @Deprecated
+    ParsedPackage setApplicationInfoResourcePath(String applicationInfoResourcePath);
+
+    ParsedPackage setBaseCodePath(String baseCodePath);
+
+    ParsedPackage setCodePath(String codePath);
+
+    ParsedPackage setCpuAbiOverride(String cpuAbiOverride);
+
+    ParsedPackage setNativeLibraryDir(String nativeLibraryDir);
+
+    ParsedPackage setNativeLibraryRootDir(String nativeLibraryRootDir);
+
+    ParsedPackage setPackageName(String packageName);
+
+    ParsedPackage setPrimaryCpuAbi(String primaryCpuAbi);
+
+    ParsedPackage setProcessName(String processName);
+
+    ParsedPackage setRealPackage(String realPackage);
+
+    ParsedPackage setSecondaryCpuAbi(String secondaryCpuAbi);
+
+    ParsedPackage setSigningDetails(PackageParser.SigningDetails signingDetails);
+
+    ParsedPackage setSplitCodePaths(String[] splitCodePaths);
+
+    ParsedPackage initForUser(int userId);
+
+    ParsedPackage setNativeLibraryRootRequiresIsa(boolean nativeLibraryRootRequiresIsa);
+
+    ParsedPackage setAllComponentsDirectBootAware(boolean allComponentsDirectBootAware);
+
+    ParsedPackage setFactoryTest(boolean factoryTest);
+
+    ParsedPackage markNotActivitiesAsNotExportedIfSingleUser();
+
+    ParsedPackage setOdm(boolean odm);
+
+    ParsedPackage setOem(boolean oem);
+
+    ParsedPackage setPrivileged(boolean privileged);
+
+    ParsedPackage setProduct(boolean product);
+
+    ParsedPackage setSignedWithPlatformKey(boolean signedWithPlatformKey);
+
+    ParsedPackage setSystem(boolean system);
+
+    ParsedPackage setSystemExt(boolean systemExt);
+
+    ParsedPackage setUpdatedSystemApp(boolean updatedSystemApp);
+
+    ParsedPackage setVendor(boolean vendor);
+
+    ParsedPackage removePermission(int index);
+
+    ParsedPackage removeUsesLibrary(String libraryName);
+
+    ParsedPackage removeUsesOptionalLibrary(String libraryName);
+
+    ParsedPackage setApplicationInfoBaseResourcePath(String applicationInfoBaseResourcePath);
+
+    ParsedPackage setApplicationInfoSplitResourcePaths(
+            String[] applicationInfoSplitResourcePaths);
+
+    ParsedPackage setApplicationVolumeUuid(String applicationVolumeUuid);
+
+    ParsedPackage setCoreApp(boolean coreApp);
+
+    ParsedPackage setIsStub(boolean isStub);
+
+    // TODO(b/135203078): Remove entirely
+    ParsedPackage setPackageSettingCallback(PackageSettingCallback packageSettingCallback);
+
+    ParsedPackage setRestrictUpdateHash(byte[] restrictUpdateHash);
+
+    ParsedPackage setSeInfo(String seInfo);
+
+    ParsedPackage setSeInfoUser(String seInfoUser);
+
+    ParsedPackage setSecondaryNativeLibraryDir(String secondaryNativeLibraryDir);
+
+    ParsedPackage setUid(int uid);
+
+    ParsedPackage setVersionCode(int versionCode);
+
+    ParsedPackage setVersionCodeMajor(int versionCodeMajor);
+
+    // TODO(b/135203078): Move logic earlier in parse chain so nothing needs to be reverted
+    ParsedPackage setDefaultToDeviceProtectedStorage(boolean defaultToDeviceProtectedStorage);
+
+    ParsedPackage setDirectBootAware(boolean directBootAware);
+
+    ParsedPackage setPersistent(boolean persistent);
+
+    interface PackageSettingCallback {
+        default void setAndroidPackage(AndroidPackage pkg){}
+    }
+}
diff --git a/core/java/android/content/pm/parsing/ParsingPackage.java b/core/java/android/content/pm/parsing/ParsingPackage.java
new file mode 100644
index 0000000..43c1f6e
--- /dev/null
+++ b/core/java/android/content/pm/parsing/ParsingPackage.java
@@ -0,0 +1,327 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm.parsing;
+
+import android.annotation.Nullable;
+import android.content.Intent;
+import android.content.pm.ConfigurationInfo;
+import android.content.pm.FeatureGroupInfo;
+import android.content.pm.FeatureInfo;
+import android.content.pm.PackageParser;
+import android.content.pm.parsing.ComponentParseUtils.ParsedActivity;
+import android.content.pm.parsing.ComponentParseUtils.ParsedActivityIntentInfo;
+import android.content.pm.parsing.ComponentParseUtils.ParsedInstrumentation;
+import android.content.pm.parsing.ComponentParseUtils.ParsedPermission;
+import android.content.pm.parsing.ComponentParseUtils.ParsedPermissionGroup;
+import android.content.pm.parsing.ComponentParseUtils.ParsedProvider;
+import android.content.pm.parsing.ComponentParseUtils.ParsedService;
+import android.os.Bundle;
+import android.util.ArraySet;
+import android.util.SparseArray;
+
+import java.security.PublicKey;
+
+/**
+ * Methods used for mutation during direct package parsing.
+ *
+ * Java disallows defining this as an inner interface, so this must be a separate file.
+ *
+ * @hide
+ */
+public interface ParsingPackage extends AndroidPackage {
+
+    ParsingPackage addActivity(ParsedActivity parsedActivity);
+
+    ParsingPackage addAdoptPermission(String adoptPermission);
+
+    ParsingPackage addConfigPreference(ConfigurationInfo configPreference);
+
+    ParsingPackage addFeatureGroup(FeatureGroupInfo featureGroup);
+
+    ParsingPackage addImplicitPermission(String permission);
+
+    ParsingPackage addInstrumentation(ParsedInstrumentation instrumentation);
+
+    ParsingPackage addKeySet(String keySetName, PublicKey publicKey);
+
+    ParsingPackage addLibraryName(String libraryName);
+
+    ParsingPackage addOriginalPackage(String originalPackage);
+
+    ParsingPackage addPermission(ParsedPermission permission);
+
+    ParsingPackage addPermissionGroup(ParsedPermissionGroup permissionGroup);
+
+    ParsingPackage addPreferredActivityFilter(ParsedActivityIntentInfo activityIntentInfo);
+
+    ParsingPackage addProtectedBroadcast(String protectedBroadcast);
+
+    ParsingPackage addProvider(ParsedProvider parsedProvider);
+
+    ParsingPackage addReceiver(ParsedActivity parsedReceiver);
+
+    ParsingPackage addReqFeature(FeatureInfo reqFeature);
+
+    ParsingPackage addRequestedPermission(String permission);
+
+    ParsingPackage addService(ParsedService parsedService);
+
+    ParsingPackage addUsesLibrary(String libraryName);
+
+    ParsingPackage addUsesOptionalLibrary(String libraryName);
+
+    ParsingPackage addUsesStaticLibrary(String libraryName);
+
+    ParsingPackage addUsesStaticLibraryCertDigests(String[] certSha256Digests);
+
+    ParsingPackage addUsesStaticLibraryVersion(long version);
+
+    ParsingPackage addQueriesIntent(Intent intent);
+
+    ParsingPackage addQueriesPackage(String packageName);
+
+    ParsingPackage asSplit(
+            String[] splitNames,
+            String[] splitCodePaths,
+            int[] splitRevisionCodes,
+            @Nullable SparseArray<int[]> splitDependencies
+    );
+
+    ParsingPackage setAppMetaData(Bundle appMetaData);
+
+    ParsingPackage setForceQueryable(boolean forceQueryable);
+
+    ParsingPackage setMaxAspectRatio(float maxAspectRatio);
+
+    ParsingPackage setMinAspectRatio(float minAspectRatio);
+
+    ParsingPackage setName(String name);
+
+    ParsingPackage setPermission(String permission);
+
+    ParsingPackage setProcessName(String processName);
+
+    ParsingPackage setSharedUserId(String sharedUserId);
+
+    ParsingPackage setStaticSharedLibName(String staticSharedLibName);
+
+    ParsingPackage setTaskAffinity(String taskAffinity);
+
+    ParsingPackage setTargetSdkVersion(int targetSdkVersion);
+
+    ParsingPackage setUiOptions(int uiOptions);
+
+    ParsingPackage setBaseHardwareAccelerated(boolean baseHardwareAccelerated);
+
+    ParsingPackage setActivitiesResizeModeResizeable(boolean resizeable);
+
+    ParsingPackage setActivitiesResizeModeResizeableViaSdkVersion(boolean resizeableViaSdkVersion);
+
+    ParsingPackage setAllowAudioPlaybackCapture(boolean allowAudioPlaybackCapture);
+
+    ParsingPackage setAllowBackup(boolean allowBackup);
+
+    ParsingPackage setAllowClearUserData(boolean allowClearUserData);
+
+    ParsingPackage setAllowClearUserDataOnFailedRestore(boolean allowClearUserDataOnFailedRestore);
+
+    ParsingPackage setAllowTaskReparenting(boolean allowTaskReparenting);
+
+    ParsingPackage setIsOverlay(boolean isOverlay);
+
+    ParsingPackage setBackupInForeground(boolean backupInForeground);
+
+    ParsingPackage setCantSaveState(boolean cantSaveState);
+
+    ParsingPackage setDebuggable(boolean debuggable);
+
+    ParsingPackage setDefaultToDeviceProtectedStorage(boolean defaultToDeviceProtectedStorage);
+
+    ParsingPackage setDirectBootAware(boolean directBootAware);
+
+    ParsingPackage setExternalStorage(boolean externalStorage);
+
+    ParsingPackage setExtractNativeLibs(boolean extractNativeLibs);
+
+    ParsingPackage setFullBackupOnly(boolean fullBackupOnly);
+
+    ParsingPackage setHasCode(boolean hasCode);
+
+    ParsingPackage setHasFragileUserData(boolean hasFragileUserData);
+
+    ParsingPackage setIsGame(boolean isGame);
+
+    ParsingPackage setIsolatedSplitLoading(boolean isolatedSplitLoading);
+
+    ParsingPackage setKillAfterRestore(boolean killAfterRestore);
+
+    ParsingPackage setLargeHeap(boolean largeHeap);
+
+    ParsingPackage setMultiArch(boolean multiArch);
+
+    ParsingPackage setPartiallyDirectBootAware(boolean partiallyDirectBootAware);
+
+    ParsingPackage setPersistent(boolean persistent);
+
+    ParsingPackage setProfileableByShell(boolean profileableByShell);
+
+    ParsingPackage setRequestLegacyExternalStorage(boolean requestLegacyExternalStorage);
+
+    ParsingPackage setRestoreAnyVersion(boolean restoreAnyVersion);
+
+    ParsingPackage setSplitHasCode(int splitIndex, boolean splitHasCode);
+
+    ParsingPackage setStaticSharedLibrary(boolean staticSharedLibrary);
+
+    ParsingPackage setSupportsRtl(boolean supportsRtl);
+
+    ParsingPackage setTestOnly(boolean testOnly);
+
+    ParsingPackage setUseEmbeddedDex(boolean useEmbeddedDex);
+
+    ParsingPackage setUsesCleartextTraffic(boolean usesCleartextTraffic);
+
+    ParsingPackage setUsesNonSdkApi(boolean usesNonSdkApi);
+
+    ParsingPackage setVisibleToInstantApps(boolean visibleToInstantApps);
+
+    ParsingPackage setVmSafeMode(boolean vmSafeMode);
+
+    ParsingPackage removeUsesOptionalLibrary(String libraryName);
+
+    ParsingPackage setAnyDensity(int anyDensity);
+
+    ParsingPackage setAppComponentFactory(String appComponentFactory);
+
+    ParsingPackage setApplicationVolumeUuid(String applicationVolumeUuid);
+
+    ParsingPackage setBackupAgentName(String backupAgentName);
+
+    ParsingPackage setBanner(int banner);
+
+    ParsingPackage setCategory(int category);
+
+    ParsingPackage setClassLoaderName(String classLoaderName);
+
+    ParsingPackage setClassName(String className);
+
+    ParsingPackage setCodePath(String codePath);
+
+    ParsingPackage setCompatibleWidthLimitDp(int compatibleWidthLimitDp);
+
+    ParsingPackage setDescriptionRes(int descriptionRes);
+
+    ParsingPackage setEnabled(boolean enabled);
+
+    ParsingPackage setFullBackupContent(int fullBackupContent);
+
+    ParsingPackage setHasDomainUrls(boolean hasDomainUrls);
+
+    ParsingPackage setIcon(int icon);
+
+    ParsingPackage setIconRes(int iconRes);
+
+    ParsingPackage setInstallLocation(int installLocation);
+
+    ParsingPackage setLabelRes(int labelRes);
+
+    ParsingPackage setLargestWidthLimitDp(int largestWidthLimitDp);
+
+    ParsingPackage setLogo(int logo);
+
+    ParsingPackage setManageSpaceActivityName(String manageSpaceActivityName);
+
+    ParsingPackage setMinSdkVersion(int minSdkVersion);
+
+    ParsingPackage setNetworkSecurityConfigRes(int networkSecurityConfigRes);
+
+    ParsingPackage setNonLocalizedLabel(CharSequence nonLocalizedLabel);
+
+    ParsingPackage setOverlayCategory(String overlayCategory);
+
+    ParsingPackage setOverlayIsStatic(boolean overlayIsStatic);
+
+    ParsingPackage setOverlayPriority(int overlayPriority);
+
+    ParsingPackage setOverlayTarget(String overlayTarget);
+
+    ParsingPackage setOverlayTargetName(String overlayTargetName);
+
+    ParsingPackage setRealPackage(String realPackage);
+
+    ParsingPackage setRequiredAccountType(String requiredAccountType);
+
+    ParsingPackage setRequiredForAllUsers(boolean requiredForAllUsers);
+
+    ParsingPackage setRequiresSmallestWidthDp(int requiresSmallestWidthDp);
+
+    ParsingPackage setResizeable(int resizeable);
+
+    ParsingPackage setRestrictUpdateHash(byte[] restrictUpdateHash);
+
+    ParsingPackage setRestrictedAccountType(String restrictedAccountType);
+
+    ParsingPackage setRoundIconRes(int roundIconRes);
+
+    ParsingPackage setSharedUserLabel(int sharedUserLabel);
+
+    ParsingPackage setSigningDetails(PackageParser.SigningDetails signingDetails);
+
+    ParsingPackage setSplitClassLoaderName(int splitIndex, String classLoaderName);
+
+    ParsingPackage setStaticSharedLibVersion(long staticSharedLibVersion);
+
+    ParsingPackage setSupportsLargeScreens(int supportsLargeScreens);
+
+    ParsingPackage setSupportsNormalScreens(int supportsNormalScreens);
+
+    ParsingPackage setSupportsSmallScreens(int supportsSmallScreens);
+
+    ParsingPackage setSupportsXLargeScreens(int supportsXLargeScreens);
+
+    ParsingPackage setTargetSandboxVersion(int targetSandboxVersion);
+
+    ParsingPackage setTheme(int theme);
+
+    ParsingPackage setUpgradeKeySets(ArraySet<String> upgradeKeySets);
+
+    ParsingPackage setUse32BitAbi(boolean use32BitAbi);
+
+    ParsingPackage setVolumeUuid(String volumeUuid);
+
+    ParsingPackage setZygotePreloadName(String zygotePreloadName);
+
+    ParsingPackage sortActivities();
+
+    ParsingPackage sortReceivers();
+
+    ParsingPackage sortServices();
+
+    ParsedPackage hideAsParsed();
+
+    ParsingPackage setBaseRevisionCode(int baseRevisionCode);
+
+    ParsingPackage setPreferredOrder(int preferredOrder);
+
+    ParsingPackage setVersionName(String versionName);
+
+    ParsingPackage setCompileSdkVersion(int compileSdkVersion);
+
+    ParsingPackage setCompileSdkVersionCodename(String compileSdkVersionCodename);
+
+    boolean usesCompatibilityMode();
+}
diff --git a/core/java/android/content/pm/parsing/library/AndroidHidlUpdater.java b/core/java/android/content/pm/parsing/library/AndroidHidlUpdater.java
new file mode 100644
index 0000000..81b4bc5
--- /dev/null
+++ b/core/java/android/content/pm/parsing/library/AndroidHidlUpdater.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.content.pm.parsing.library;
+
+import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_HIDL_BASE;
+import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_HIDL_MANAGER;
+
+import android.content.pm.parsing.ParsedPackage;
+import android.os.Build;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * Updates a package to ensure that if it targets <= P that the android.hidl.base-V1.0-java
+ * and android.hidl.manager-V1.0-java libraries are included by default.
+ *
+ * @hide
+ */
+@VisibleForTesting
+public class AndroidHidlUpdater extends PackageSharedLibraryUpdater {
+
+    @Override
+    public void updatePackage(ParsedPackage parsedPackage) {
+        // This was the default <= P and is maintained for backwards compatibility.
+        boolean isLegacy = parsedPackage.getTargetSdkVersion() <= Build.VERSION_CODES.P;
+        // Only system apps use these libraries
+        boolean isSystem = parsedPackage.isSystemApp() || parsedPackage.isUpdatedSystemApp();
+
+        if (isLegacy && isSystem) {
+            prefixRequiredLibrary(parsedPackage, ANDROID_HIDL_BASE);
+            prefixRequiredLibrary(parsedPackage, ANDROID_HIDL_MANAGER);
+        } else {
+            removeLibrary(parsedPackage, ANDROID_HIDL_BASE);
+            removeLibrary(parsedPackage, ANDROID_HIDL_MANAGER);
+        }
+    }
+}
diff --git a/core/java/android/content/pm/AndroidTestBaseUpdater.java b/core/java/android/content/pm/parsing/library/AndroidTestBaseUpdater.java
similarity index 88%
rename from core/java/android/content/pm/AndroidTestBaseUpdater.java
rename to core/java/android/content/pm/parsing/library/AndroidTestBaseUpdater.java
index 18d3ba3..fc02a86 100644
--- a/core/java/android/content/pm/AndroidTestBaseUpdater.java
+++ b/core/java/android/content/pm/parsing/library/AndroidTestBaseUpdater.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2019 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -13,10 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.content.pm;
+package android.content.pm.parsing.library;
 
-import static android.content.pm.SharedLibraryNames.ANDROID_TEST_BASE;
-import static android.content.pm.SharedLibraryNames.ANDROID_TEST_RUNNER;
+import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_BASE;
+import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_RUNNER;
 
 import android.compat.annotation.ChangeId;
 import android.compat.annotation.EnabledAfter;
@@ -72,7 +72,7 @@
     }
 
     @Override
-    public void updatePackage(Package pkg) {
+    public void updatePackage(ParsedPackage parsedPackage) {
         // Packages targeted at <= Q expect the classes in the android.test.base library
         // to be accessible so this maintains backward compatibility by adding the
         // android.test.base library to those packages.
@@ -82,7 +82,7 @@
             // If a package already depends on android.test.runner then add a dependency on
             // android.test.base because android.test.runner depends on classes from the
             // android.test.base library.
-            prefixImplicitDependency(pkg, ANDROID_TEST_RUNNER, ANDROID_TEST_BASE);
+            prefixImplicitDependency(parsedPackage, ANDROID_TEST_RUNNER, ANDROID_TEST_BASE);
         }
     }
 }
diff --git a/core/java/android/content/pm/OrgApacheHttpLegacyUpdater.java b/core/java/android/content/pm/parsing/library/OrgApacheHttpLegacyUpdater.java
similarity index 67%
rename from core/java/android/content/pm/OrgApacheHttpLegacyUpdater.java
rename to core/java/android/content/pm/parsing/library/OrgApacheHttpLegacyUpdater.java
index 707443b..613a06b 100644
--- a/core/java/android/content/pm/OrgApacheHttpLegacyUpdater.java
+++ b/core/java/android/content/pm/parsing/library/OrgApacheHttpLegacyUpdater.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2019 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -13,11 +13,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.content.pm;
+package android.content.pm.parsing.library;
 
-import static android.content.pm.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY;
+import static android.content.pm.parsing.library.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY;
 
-import android.content.pm.PackageParser.Package;
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.ParsedPackage;
 import android.os.Build;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -31,18 +32,17 @@
 @VisibleForTesting
 public class OrgApacheHttpLegacyUpdater extends PackageSharedLibraryUpdater {
 
-    private static boolean apkTargetsApiLevelLessThanOrEqualToOMR1(Package pkg) {
-        int targetSdkVersion = pkg.applicationInfo.targetSdkVersion;
-        return targetSdkVersion < Build.VERSION_CODES.P;
+    private static boolean apkTargetsApiLevelLessThanOrEqualToOMR1(AndroidPackage pkg) {
+        return pkg.getTargetSdkVersion() < Build.VERSION_CODES.P;
     }
 
     @Override
-    public void updatePackage(Package pkg) {
+    public void updatePackage(ParsedPackage parsedPackage) {
         // Packages targeted at <= O_MR1 expect the classes in the org.apache.http.legacy library
         // to be accessible so this maintains backward compatibility by adding the
         // org.apache.http.legacy library to those packages.
-        if (apkTargetsApiLevelLessThanOrEqualToOMR1(pkg)) {
-            prefixRequiredLibrary(pkg, ORG_APACHE_HTTP_LEGACY);
+        if (apkTargetsApiLevelLessThanOrEqualToOMR1(parsedPackage)) {
+            prefixRequiredLibrary(parsedPackage, ORG_APACHE_HTTP_LEGACY);
         }
     }
 }
diff --git a/core/java/android/content/pm/PackageBackwardCompatibility.java b/core/java/android/content/pm/parsing/library/PackageBackwardCompatibility.java
similarity index 80%
rename from core/java/android/content/pm/PackageBackwardCompatibility.java
rename to core/java/android/content/pm/parsing/library/PackageBackwardCompatibility.java
index 4331bd4..1220fc4 100644
--- a/core/java/android/content/pm/PackageBackwardCompatibility.java
+++ b/core/java/android/content/pm/parsing/library/PackageBackwardCompatibility.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2019 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,14 +14,14 @@
  * limitations under the License.
  */
 
-package android.content.pm;
+package android.content.pm.parsing.library;
 
-import static android.content.pm.SharedLibraryNames.ANDROID_TEST_BASE;
-import static android.content.pm.SharedLibraryNames.ANDROID_TEST_MOCK;
-import static android.content.pm.SharedLibraryNames.ANDROID_TEST_RUNNER;
-import static android.content.pm.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY;
+import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_BASE;
+import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_MOCK;
+import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_RUNNER;
+import static android.content.pm.parsing.library.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY;
 
-import android.content.pm.PackageParser.Package;
+import android.content.pm.parsing.ParsedPackage;
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -31,7 +31,7 @@
 import java.util.function.Supplier;
 
 /**
- * Modifies {@link Package} in order to maintain backwards compatibility.
+ * Modifies {@link ParsedPackage} in order to maintain backwards compatibility.
  *
  * @hide
  */
@@ -60,7 +60,7 @@
         // will remove any references to org.apache.http.library from the package so that it does
         // not try and load the library when it is on the bootclasspath.
         boolean bootClassPathContainsATB = !addOptionalUpdater(packageUpdaters,
-                "android.content.pm.AndroidTestBaseUpdater",
+                "android.content.pm.parsing.library.AndroidTestBaseUpdater",
                 RemoveUnnecessaryAndroidTestBaseLibrary::new);
 
         PackageSharedLibraryUpdater[] updaterArray = packageUpdaters
@@ -123,20 +123,20 @@
     }
 
     /**
-     * Modify the shared libraries in the supplied {@link Package} to maintain backwards
+     * Modify the shared libraries in the supplied {@link ParsedPackage} to maintain backwards
      * compatibility.
      *
-     * @param pkg the {@link Package} to modify.
+     * @param parsedPackage the {@link ParsedPackage} to modify.
      */
     @VisibleForTesting
-    public static void modifySharedLibraries(Package pkg) {
-        INSTANCE.updatePackage(pkg);
+    public static void modifySharedLibraries(ParsedPackage parsedPackage) {
+        INSTANCE.updatePackage(parsedPackage);
     }
 
     @Override
-    public void updatePackage(Package pkg) {
+    public void updatePackage(ParsedPackage parsedPackage) {
         for (PackageSharedLibraryUpdater packageUpdater : mPackageUpdaters) {
-            packageUpdater.updatePackage(pkg);
+            packageUpdater.updatePackage(parsedPackage);
         }
     }
 
@@ -161,10 +161,10 @@
     public static class AndroidTestRunnerSplitUpdater extends PackageSharedLibraryUpdater {
 
         @Override
-        public void updatePackage(Package pkg) {
+        public void updatePackage(ParsedPackage parsedPackage) {
             // android.test.runner has a dependency on android.test.mock so if android.test.runner
             // is present but android.test.mock is not then add android.test.mock.
-            prefixImplicitDependency(pkg, ANDROID_TEST_RUNNER, ANDROID_TEST_MOCK);
+            prefixImplicitDependency(parsedPackage, ANDROID_TEST_RUNNER, ANDROID_TEST_MOCK);
         }
     }
 
@@ -177,8 +177,8 @@
             extends PackageSharedLibraryUpdater {
 
         @Override
-        public void updatePackage(Package pkg) {
-            removeLibrary(pkg, ORG_APACHE_HTTP_LEGACY);
+        public void updatePackage(ParsedPackage parsedPackage) {
+            removeLibrary(parsedPackage, ORG_APACHE_HTTP_LEGACY);
         }
 
     }
@@ -192,8 +192,8 @@
             extends PackageSharedLibraryUpdater {
 
         @Override
-        public void updatePackage(Package pkg) {
-            removeLibrary(pkg, ANDROID_TEST_BASE);
+        public void updatePackage(ParsedPackage parsedPackage) {
+            removeLibrary(parsedPackage, ANDROID_TEST_BASE);
         }
     }
 }
diff --git a/core/java/android/content/pm/parsing/library/PackageSharedLibraryUpdater.java b/core/java/android/content/pm/parsing/library/PackageSharedLibraryUpdater.java
new file mode 100644
index 0000000..8b27d14
--- /dev/null
+++ b/core/java/android/content/pm/parsing/library/PackageSharedLibraryUpdater.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.content.pm.parsing.library;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.pm.parsing.ParsedPackage;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ArrayUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Base for classes that update a {@link ParsedPackage}'s shared libraries.
+ *
+ * @hide
+ */
+@VisibleForTesting
+public abstract class PackageSharedLibraryUpdater {
+
+    /**
+     * Update the package's shared libraries.
+     *
+     * @param parsedPackage the package to update.
+     */
+    public abstract void updatePackage(ParsedPackage parsedPackage);
+
+    static void removeLibrary(ParsedPackage parsedPackage, String libraryName) {
+        parsedPackage.removeUsesLibrary(libraryName)
+                .removeUsesOptionalLibrary(libraryName);
+    }
+
+    static @NonNull
+            <T> ArrayList<T> prefix(@Nullable ArrayList<T> cur, T val) {
+        if (cur == null) {
+            cur = new ArrayList<>();
+        }
+        cur.add(0, val);
+        return cur;
+    }
+
+    private static boolean isLibraryPresent(List<String> usesLibraries,
+            List<String> usesOptionalLibraries, String apacheHttpLegacy) {
+        return ArrayUtils.contains(usesLibraries, apacheHttpLegacy)
+                || ArrayUtils.contains(usesOptionalLibraries, apacheHttpLegacy);
+    }
+
+    /**
+     * Add an implicit dependency.
+     *
+     * <p>If the package has an existing dependency on {@code existingLibrary} then prefix it with
+     * the {@code implicitDependency} if it is not already in the list of libraries.
+     *
+     * @param parsedPackage the {@link ParsedPackage} to update.
+     * @param existingLibrary the existing library.
+     * @param implicitDependency the implicit dependency to add
+     */
+    void prefixImplicitDependency(ParsedPackage parsedPackage, String existingLibrary,
+            String implicitDependency) {
+        List<String> usesLibraries = parsedPackage.getUsesLibraries();
+        List<String> usesOptionalLibraries = parsedPackage.getUsesOptionalLibraries();
+
+        if (!isLibraryPresent(usesLibraries, usesOptionalLibraries, implicitDependency)) {
+            if (ArrayUtils.contains(usesLibraries, existingLibrary)) {
+                parsedPackage.addUsesLibrary(0, implicitDependency);
+            } else if (ArrayUtils.contains(usesOptionalLibraries, existingLibrary)) {
+                parsedPackage.addUsesOptionalLibrary(0, implicitDependency);
+            }
+        }
+    }
+
+    void prefixRequiredLibrary(ParsedPackage parsedPackage, String libraryName) {
+        List<String> usesLibraries = parsedPackage.getUsesLibraries();
+        List<String> usesOptionalLibraries = parsedPackage.getUsesOptionalLibraries();
+
+        boolean alreadyPresent = isLibraryPresent(
+                usesLibraries, usesOptionalLibraries, libraryName);
+        if (!alreadyPresent) {
+            parsedPackage.addUsesLibrary(0, libraryName);
+        }
+    }
+}
diff --git a/core/java/android/content/pm/SharedLibraryNames.java b/core/java/android/content/pm/parsing/library/SharedLibraryNames.java
similarity index 91%
rename from core/java/android/content/pm/SharedLibraryNames.java
rename to core/java/android/content/pm/parsing/library/SharedLibraryNames.java
index a607a9f..7b691c0 100644
--- a/core/java/android/content/pm/SharedLibraryNames.java
+++ b/core/java/android/content/pm/parsing/library/SharedLibraryNames.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2019 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.content.pm;
+package android.content.pm.parsing.library;
 
 /**
  * A set of shared library names
diff --git a/core/java/com/android/internal/content/NativeLibraryHelper.java b/core/java/com/android/internal/content/NativeLibraryHelper.java
index 0847fbd..6709ff5 100644
--- a/core/java/com/android/internal/content/NativeLibraryHelper.java
+++ b/core/java/com/android/internal/content/NativeLibraryHelper.java
@@ -28,9 +28,9 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageParser;
-import android.content.pm.PackageParser.Package;
 import android.content.pm.PackageParser.PackageLite;
 import android.content.pm.PackageParser.PackageParserException;
+import android.content.pm.parsing.AndroidPackage;
 import android.os.Build;
 import android.os.SELinux;
 import android.system.ErrnoException;
@@ -87,11 +87,12 @@
             }
         }
 
-        public static Handle create(Package pkg) throws IOException {
-            return create(pkg.getAllCodePaths(),
-                    (pkg.applicationInfo.flags & ApplicationInfo.FLAG_MULTIARCH) != 0,
-                    (pkg.applicationInfo.flags & ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS) != 0,
-                    (pkg.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0);
+        public static Handle create(AndroidPackage pkg) throws IOException {
+            return create(
+                    pkg.makeListAllCodePaths(),
+                    (pkg.getFlags() & ApplicationInfo.FLAG_MULTIARCH) != 0,
+                    (pkg.getFlags() & ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS) != 0,
+                    (pkg.getFlags() & ApplicationInfo.FLAG_DEBUGGABLE) != 0);
         }
 
         public static Handle create(PackageLite lite) throws IOException {
diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java
index 821022f..bc80197 100644
--- a/core/java/com/android/internal/util/ArrayUtils.java
+++ b/core/java/com/android/internal/util/ArrayUtils.java
@@ -600,6 +600,14 @@
         return cur;
     }
 
+    public static @NonNull <T> ArrayList<T> add(@Nullable ArrayList<T> cur, int index, T val) {
+        if (cur == null) {
+            cur = new ArrayList<>();
+        }
+        cur.add(index, val);
+        return cur;
+    }
+
     public static @Nullable <T> ArrayList<T> remove(@Nullable ArrayList<T> cur, T val) {
         if (cur == null) {
             return null;
diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp
index a4c504b..c009f58 100644
--- a/core/tests/coretests/Android.bp
+++ b/core/tests/coretests/Android.bp
@@ -74,7 +74,6 @@
         ":FrameworksCoreTests_install_loc_internal",
         ":FrameworksCoreTests_install_loc_sdcard",
         ":FrameworksCoreTests_install_loc_unspecified",
-        ":FrameworksCoreTests_install_multi_package",
         ":FrameworksCoreTests_install_split_base",
         ":FrameworksCoreTests_install_split_feature_a",
         ":FrameworksCoreTests_install_use_perm_good",
diff --git a/core/tests/coretests/apks/install_multi_package/Android.bp b/core/tests/coretests/apks/install_multi_package/Android.bp
deleted file mode 100644
index 249242e..0000000
--- a/core/tests/coretests/apks/install_multi_package/Android.bp
+++ /dev/null
@@ -1,6 +0,0 @@
-android_test_helper_app {
-    name: "FrameworksCoreTests_install_multi_package",
-    defaults: ["FrameworksCoreTests_apks_defaults"],
-
-    srcs: ["**/*.java"],
-}
diff --git a/core/tests/coretests/apks/install_multi_package/AndroidManifest.xml b/core/tests/coretests/apks/install_multi_package/AndroidManifest.xml
deleted file mode 100644
index 5164cae..0000000
--- a/core/tests/coretests/apks/install_multi_package/AndroidManifest.xml
+++ /dev/null
@@ -1,104 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<manifest
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.frameworks.coretests.install_multi_package">
-
-<!--
-     This manifest is has child packages with components.
--->
-
-    <uses-feature
-        android:name="com.android.frameworks.coretests.nonexistent" />
-    <uses-configuration
-        android:reqFiveWayNav="false" />
-
-    <instrumentation
-        android:name="android.test.InstrumentationTestRunner"
-        android:targetPackage="com.android.frameworks.coretests"
-        android:label="Frameworks Core Tests" />
-
-    <permission
-        android:label="test permission"
-        android:name="test_permission"
-        android:protectionLevel="normal" />
-    <uses-permission android:name="android.permission.INTERNET" />
-
-<!--
-     NOTE: This declares a child package, application, then another child
-     package, to test potential bugs that are order-dependent. Also, each
-     one varies the order.
--->
-
-    <package package="com.android.frameworks.coretests.install_multi_package.first_child">
-        <uses-permission android:name="android.permission.NFC" />
-        <!-- NOTE: A declared permission is ignored since the tag is not whitelisted. -->
-        <permission
-            android:label="test permission"
-            android:name="first_child_permission"
-            android:protectionLevel="signature" />
-        <application
-            android:hasCode="true">
-            <activity
-                android:name="com.android.frameworks.coretests.FirstChildTestActivity">
-            </activity>
-            <provider
-                android:name="com.android.frameworks.coretests.FirstChildTestProvider"
-                android:authorities="com.android.frameworks.coretests.testprovider" />
-            <receiver
-                android:name="com.android.frameworks.coretests.FirstChildTestReceiver" />
-            <service
-                android:name="com.android.frameworks.coretests.FirstChildTestService" />
-        </application>
-    </package>
-
-    <application
-        android:hasCode="true">
-        <service
-            android:name="com.android.frameworks.coretests.TestService" />
-        <activity
-            android:name="com.android.frameworks.coretests.TestActivity">
-        </activity>
-        <provider
-            android:name="com.android.frameworks.coretests.TestProvider"
-            android:authorities="com.android.frameworks.coretests.testprovider" />
-        <receiver
-            android:name="com.android.frameworks.coretests.TestReceiver" />
-    </application>
-
-    <package package="com.android.frameworks.coretests.blah.second_child">
-        <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
-        <uses-permission-sdk-23 android:name="android.permission.READ_CONTACTS" />
-        <!-- NOTE: A declared permission is ignored since the tag is not whitelisted. -->
-        <permission
-            android:label="test permission"
-            android:name="second_child_permission"
-            android:protectionLevel="dangerous" />
-        <application
-            android:hasCode="true">
-            <receiver
-                android:name="com.android.frameworks.coretests.SecondChildTestReceiver" />
-            <service
-                android:name="com.android.frameworks.coretests.SecondChildTestService" />
-            <activity
-                android:name="com.android.frameworks.coretests.SecondChildTestActivity">
-            </activity>
-            <provider
-                android:name="com.android.frameworks.coretests.SecondChildTestProvider"
-                android:authorities="com.android.frameworks.coretests.testprovider" />
-        </application>
-    </package>
-</manifest>
diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestActivity.java b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestActivity.java
deleted file mode 100644
index 57afcb0..0000000
--- a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestActivity.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package com.android.frameworks.coretests;
-
-import android.app.Activity;
-
-public class FirstChildTestActivity extends Activity {
-
-}
diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestProvider.java b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestProvider.java
deleted file mode 100644
index 2816865..0000000
--- a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestProvider.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package com.android.frameworks.coretests;
-
-import android.content.ContentProvider;
-import android.content.ContentValues;
-import android.database.Cursor;
-import android.net.Uri;
-
-public class FirstChildTestProvider extends ContentProvider {
-
-    @Override
-    public boolean onCreate() {
-        return false;
-    }
-
-    @Override
-    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
-            String sortOrder) {
-        return null;
-    }
-
-    @Override
-    public String getType(Uri uri) {
-        return null;
-    }
-
-    @Override
-    public Uri insert(Uri uri, ContentValues values) {
-        return null;
-    }
-
-    @Override
-    public int delete(Uri uri, String selection, String[] selectionArgs) {
-        return 0;
-    }
-
-    @Override
-    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
-        return 0;
-    }
-}
diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestReceiver.java b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestReceiver.java
deleted file mode 100644
index ffe84b7..0000000
--- a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestReceiver.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package com.android.frameworks.coretests;
-
-import android.content.ContentProvider;
-import android.content.ContentValues;
-import android.database.Cursor;
-import android.net.Uri;
-
-public class FirstChildTestReceiver extends ContentProvider {
-
-    @Override
-    public boolean onCreate() {
-        return false;
-    }
-
-    @Override
-    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
-            String sortOrder) {
-        return null;
-    }
-
-    @Override
-    public String getType(Uri uri) {
-        return null;
-    }
-
-    @Override
-    public Uri insert(Uri uri, ContentValues values) {
-        return null;
-    }
-
-    @Override
-    public int delete(Uri uri, String selection, String[] selectionArgs) {
-        return 0;
-    }
-
-    @Override
-    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
-        return 0;
-    }
-}
diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestService.java b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestService.java
deleted file mode 100644
index faa6e9c..0000000
--- a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestService.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package com.android.frameworks.coretests;
-
-import android.app.Service;
-import android.content.Intent;
-import android.os.IBinder;
-
-public class FirstChildTestService extends Service {
-
-    @Override
-    public IBinder onBind(Intent intent) {
-        return null;
-    }
-}
diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestActivity.java b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestActivity.java
deleted file mode 100644
index e89f264..0000000
--- a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestActivity.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package com.android.frameworks.coretests;
-
-import android.app.Activity;
-
-public class SecondChildTestActivity extends Activity {
-
-}
diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestProvider.java b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestProvider.java
deleted file mode 100644
index 2bd40a5..0000000
--- a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestProvider.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package com.android.frameworks.coretests;
-
-import android.content.ContentProvider;
-import android.content.ContentValues;
-import android.database.Cursor;
-import android.net.Uri;
-
-public class SecondChildTestProvider extends ContentProvider {
-
-    @Override
-    public boolean onCreate() {
-        return false;
-    }
-
-    @Override
-    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
-            String sortOrder) {
-        return null;
-    }
-
-    @Override
-    public String getType(Uri uri) {
-        return null;
-    }
-
-    @Override
-    public Uri insert(Uri uri, ContentValues values) {
-        return null;
-    }
-
-    @Override
-    public int delete(Uri uri, String selection, String[] selectionArgs) {
-        return 0;
-    }
-
-    @Override
-    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
-        return 0;
-    }
-}
diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestReceiver.java b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestReceiver.java
deleted file mode 100644
index a6c4ddc..0000000
--- a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestReceiver.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package com.android.frameworks.coretests;
-
-import android.content.ContentProvider;
-import android.content.ContentValues;
-import android.database.Cursor;
-import android.net.Uri;
-
-public class SecondChildTestReceiver extends ContentProvider {
-
-    @Override
-    public boolean onCreate() {
-        return false;
-    }
-
-    @Override
-    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
-            String sortOrder) {
-        return null;
-    }
-
-    @Override
-    public String getType(Uri uri) {
-        return null;
-    }
-
-    @Override
-    public Uri insert(Uri uri, ContentValues values) {
-        return null;
-    }
-
-    @Override
-    public int delete(Uri uri, String selection, String[] selectionArgs) {
-        return 0;
-    }
-
-    @Override
-    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
-        return 0;
-    }
-}
diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestService.java b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestService.java
deleted file mode 100644
index 1e721aa..0000000
--- a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestService.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package com.android.frameworks.coretests;
-
-import android.app.Service;
-import android.content.Intent;
-import android.os.IBinder;
-
-public class SecondChildTestService extends Service {
-
-    @Override
-    public IBinder onBind(Intent intent) {
-        return null;
-    }
-}
diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestActivity.java b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestActivity.java
deleted file mode 100644
index 10d0551..0000000
--- a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestActivity.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package com.android.frameworks.coretests;
-
-import android.app.Activity;
-
-public class TestActivity extends Activity {
-
-}
diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestProvider.java b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestProvider.java
deleted file mode 100644
index 59f9f10..0000000
--- a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestProvider.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package com.android.frameworks.coretests;
-
-import android.content.ContentProvider;
-import android.content.ContentValues;
-import android.database.Cursor;
-import android.net.Uri;
-
-public class TestProvider extends ContentProvider {
-
-    @Override
-    public boolean onCreate() {
-        return false;
-    }
-
-    @Override
-    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
-            String sortOrder) {
-        return null;
-    }
-
-    @Override
-    public String getType(Uri uri) {
-        return null;
-    }
-
-    @Override
-    public Uri insert(Uri uri, ContentValues values) {
-        return null;
-    }
-
-    @Override
-    public int delete(Uri uri, String selection, String[] selectionArgs) {
-        return 0;
-    }
-
-    @Override
-    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
-        return 0;
-    }
-}
diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestReceiver.java b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestReceiver.java
deleted file mode 100644
index 21f6263..0000000
--- a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestReceiver.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package com.android.frameworks.coretests;
-
-import android.content.ContentProvider;
-import android.content.ContentValues;
-import android.database.Cursor;
-import android.net.Uri;
-
-public class TestReceiver extends ContentProvider {
-
-    @Override
-    public boolean onCreate() {
-        return false;
-    }
-
-    @Override
-    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
-            String sortOrder) {
-        return null;
-    }
-
-    @Override
-    public String getType(Uri uri) {
-        return null;
-    }
-
-    @Override
-    public Uri insert(Uri uri, ContentValues values) {
-        return null;
-    }
-
-    @Override
-    public int delete(Uri uri, String selection, String[] selectionArgs) {
-        return 0;
-    }
-
-    @Override
-    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
-        return 0;
-    }
-}
diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestService.java b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestService.java
deleted file mode 100644
index b330e75..0000000
--- a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestService.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package com.android.frameworks.coretests;
-
-import android.app.Service;
-import android.content.Intent;
-import android.os.IBinder;
-
-public class TestService extends Service {
-
-    @Override
-    public IBinder onBind(Intent intent) {
-        return null;
-    }
-}
diff --git a/core/tests/coretests/src/android/content/pm/AndroidHidlUpdaterTest.java b/core/tests/coretests/src/android/content/pm/AndroidHidlUpdaterTest.java
deleted file mode 100644
index cc48239..0000000
--- a/core/tests/coretests/src/android/content/pm/AndroidHidlUpdaterTest.java
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.content.pm;
-
-import static android.content.pm.PackageBuilder.builder;
-import static android.content.pm.SharedLibraryNames.ANDROID_HIDL_BASE;
-import static android.content.pm.SharedLibraryNames.ANDROID_HIDL_MANAGER;
-
-import android.os.Build;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/**
- * Test for {@link AndroidHidlUpdater}
- */
-@SmallTest
-@RunWith(JUnit4.class)
-public class AndroidHidlUpdaterTest extends PackageSharedLibraryUpdaterTest {
-
-    private static final String OTHER_LIBRARY = "other.library";
-
-    @Test
-    public void targeted_at_P() {
-        PackageBuilder before = builder()
-                .targetSdkVersion(Build.VERSION_CODES.P);
-
-        // no change, not system
-        checkBackwardsCompatibility(before, before);
-    }
-
-    @Test
-    public void targeted_at_P_system() {
-        PackageBuilder before = builder().asSystemApp()
-                .targetSdkVersion(Build.VERSION_CODES.P);
-
-        // Should add both HIDL libraries
-        PackageBuilder after = builder().asSystemApp()
-                .targetSdkVersion(Build.VERSION_CODES.P)
-                .requiredLibraries(ANDROID_HIDL_MANAGER, ANDROID_HIDL_BASE);
-
-        checkBackwardsCompatibility(before, after);
-    }
-
-    @Test
-    public void targeted_at_P_not_empty_usesLibraries() {
-        PackageBuilder before = builder()
-                .targetSdkVersion(Build.VERSION_CODES.P)
-                .requiredLibraries(OTHER_LIBRARY);
-
-        // no change, not system
-        checkBackwardsCompatibility(before, before);
-    }
-
-    @Test
-    public void targeted_at_P_not_empty_usesLibraries_system() {
-        PackageBuilder before = builder().asSystemApp()
-                .targetSdkVersion(Build.VERSION_CODES.P)
-                .requiredLibraries(OTHER_LIBRARY);
-
-        // The hidl jars should be added at the start of the list because it
-        // is not on the bootclasspath and the package targets pre-P.
-        PackageBuilder after = builder().asSystemApp()
-                .targetSdkVersion(Build.VERSION_CODES.P)
-                .requiredLibraries(ANDROID_HIDL_MANAGER, ANDROID_HIDL_BASE, OTHER_LIBRARY);
-
-        checkBackwardsCompatibility(before, after);
-    }
-
-    @Test
-    public void targeted_at_P_in_usesLibraries() {
-        PackageBuilder before = builder()
-                .targetSdkVersion(Build.VERSION_CODES.P)
-                .requiredLibraries(ANDROID_HIDL_MANAGER, ANDROID_HIDL_BASE);
-
-        PackageBuilder after = builder()
-                .targetSdkVersion(Build.VERSION_CODES.P);
-
-        // Libraries are removed because they are not available for non-system apps
-        checkBackwardsCompatibility(before, after);
-    }
-
-    @Test
-    public void targeted_at_P_in_usesLibraries_system() {
-        PackageBuilder before = builder().asSystemApp()
-                .targetSdkVersion(Build.VERSION_CODES.P)
-                .requiredLibraries(ANDROID_HIDL_MANAGER, ANDROID_HIDL_BASE);
-
-        // No change is required because the package explicitly requests the HIDL libraries
-        // and is targeted at the current version so does not need backwards compatibility.
-        checkBackwardsCompatibility(before, before);
-    }
-
-    @Test
-    public void in_usesLibraries() {
-        PackageBuilder before = builder().requiredLibraries(ANDROID_HIDL_BASE);
-
-        // Dependency is removed, it is not available.
-        PackageBuilder after = builder();
-
-        // Libraries are removed because they are not available for apps targetting Q+
-        checkBackwardsCompatibility(before, after);
-    }
-
-    @Test
-    public void in_usesOptionalLibraries() {
-        PackageBuilder before = builder().optionalLibraries(ANDROID_HIDL_BASE);
-
-        // Dependency is removed, it is not available.
-        PackageBuilder after = builder();
-
-        // Libraries are removed because they are not available for apps targetting Q+
-        checkBackwardsCompatibility(before, after);
-    }
-
-    private void checkBackwardsCompatibility(PackageBuilder before, PackageBuilder after) {
-        checkBackwardsCompatibility(before, after, AndroidHidlUpdater::new);
-    }
-}
diff --git a/core/tests/coretests/src/android/content/pm/AndroidTestBaseUpdaterTest.java b/core/tests/coretests/src/android/content/pm/AndroidTestBaseUpdaterTest.java
deleted file mode 100644
index 03108ce..0000000
--- a/core/tests/coretests/src/android/content/pm/AndroidTestBaseUpdaterTest.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.content.pm;
-
-import static android.content.pm.PackageBuilder.builder;
-import static android.content.pm.SharedLibraryNames.ANDROID_TEST_BASE;
-
-import android.os.Build;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/**
- * Test for {@link AndroidTestBaseUpdater}
- */
-@SmallTest
-@RunWith(OptionalClassRunner.class)
-@OptionalClassRunner.OptionalClass("android.content.pm.AndroidTestBaseUpdater")
-public class AndroidTestBaseUpdaterTest extends PackageSharedLibraryUpdaterTest {
-
-    private static final String OTHER_LIBRARY = "other.library";
-
-    @Test
-    public void targeted_at_Q() {
-        PackageBuilder before = builder()
-                .targetSdkVersion(Build.VERSION_CODES.Q);
-
-        // Should add org.apache.http.legacy.
-        PackageBuilder after = builder()
-                .targetSdkVersion(Build.VERSION_CODES.Q)
-                .requiredLibraries(ANDROID_TEST_BASE);
-
-        checkBackwardsCompatibility(before, after);
-    }
-
-    @Test
-    public void targeted_at_Q_not_empty_usesLibraries() {
-        PackageBuilder before = builder()
-                .targetSdkVersion(Build.VERSION_CODES.Q)
-                .requiredLibraries(OTHER_LIBRARY);
-
-        // The org.apache.http.legacy jar should be added at the start of the list because it
-        // is not on the bootclasspath and the package targets pre-Q.
-        PackageBuilder after = builder()
-                .targetSdkVersion(Build.VERSION_CODES.Q)
-                .requiredLibraries(ANDROID_TEST_BASE, OTHER_LIBRARY);
-
-        checkBackwardsCompatibility(before, after);
-    }
-
-    @Test
-    public void targeted_at_Q_in_usesLibraries() {
-        PackageBuilder before = builder()
-                .targetSdkVersion(Build.VERSION_CODES.Q)
-                .requiredLibraries(ANDROID_TEST_BASE);
-
-        // No change is required because although org.apache.http.legacy has been removed from
-        // the bootclasspath the package explicitly requests it.
-        checkBackwardsCompatibility(before, before);
-    }
-
-    @Test
-    public void targeted_at_Q_in_usesOptionalLibraries() {
-        PackageBuilder before = builder()
-                .targetSdkVersion(Build.VERSION_CODES.Q)
-                .optionalLibraries(ANDROID_TEST_BASE);
-
-        // No change is required because although org.apache.http.legacy has been removed from
-        // the bootclasspath the package explicitly requests it.
-        checkBackwardsCompatibility(before, before);
-    }
-
-    @Test
-    public void in_usesLibraries() {
-        PackageBuilder before = builder().requiredLibraries(ANDROID_TEST_BASE);
-
-        // No change is required because the package explicitly requests org.apache.http.legacy
-        // and is targeted at the current version so does not need backwards compatibility.
-        checkBackwardsCompatibility(before, before);
-    }
-
-    @Test
-    public void in_usesOptionalLibraries() {
-        PackageBuilder before = builder().optionalLibraries(ANDROID_TEST_BASE);
-
-        // No change is required because the package explicitly requests org.apache.http.legacy
-        // and is targeted at the current version so does not need backwards compatibility.
-        checkBackwardsCompatibility(before, before);
-    }
-
-    private void checkBackwardsCompatibility(PackageBuilder before, PackageBuilder after) {
-        checkBackwardsCompatibility(before, after, AndroidTestBaseUpdater::new);
-    }
-}
diff --git a/core/tests/coretests/src/android/content/pm/AndroidTestRunnerSplitUpdaterTest.java b/core/tests/coretests/src/android/content/pm/AndroidTestRunnerSplitUpdaterTest.java
deleted file mode 100644
index 7f817d6..0000000
--- a/core/tests/coretests/src/android/content/pm/AndroidTestRunnerSplitUpdaterTest.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.content.pm;
-
-import static android.content.pm.PackageBuilder.builder;
-import static android.content.pm.SharedLibraryNames.ANDROID_TEST_MOCK;
-import static android.content.pm.SharedLibraryNames.ANDROID_TEST_RUNNER;
-
-import android.content.pm.PackageBackwardCompatibility.AndroidTestRunnerSplitUpdater;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/**
- * Test for {@link AndroidTestRunnerSplitUpdater}
- */
-@SmallTest
-@RunWith(JUnit4.class)
-public class AndroidTestRunnerSplitUpdaterTest extends PackageSharedLibraryUpdaterTest {
-
-    @Test
-    public void android_test_runner_in_usesOptionalLibraries() {
-        PackageBuilder before = builder().optionalLibraries(ANDROID_TEST_RUNNER);
-
-        PackageBuilder after = builder()
-                .optionalLibraries(ANDROID_TEST_MOCK, ANDROID_TEST_RUNNER);
-
-        checkBackwardsCompatibility(before, after);
-    }
-
-    @Test
-    public void android_test_runner_in_usesLibraries_android_test_mock_in_usesOptionalLibraries() {
-        PackageBuilder before = builder()
-                .requiredLibraries(ANDROID_TEST_RUNNER)
-                .optionalLibraries(ANDROID_TEST_MOCK);
-
-        PackageBuilder after = builder()
-                .requiredLibraries(ANDROID_TEST_RUNNER)
-                .optionalLibraries(ANDROID_TEST_MOCK);
-
-        checkBackwardsCompatibility(before, after);
-    }
-
-    private void checkBackwardsCompatibility(PackageBuilder before, PackageBuilder after) {
-        checkBackwardsCompatibility(before, after, AndroidTestRunnerSplitUpdater::new);
-    }
-}
diff --git a/core/tests/coretests/src/android/content/pm/OrgApacheHttpLegacyUpdaterTest.java b/core/tests/coretests/src/android/content/pm/OrgApacheHttpLegacyUpdaterTest.java
deleted file mode 100644
index 834a0bb..0000000
--- a/core/tests/coretests/src/android/content/pm/OrgApacheHttpLegacyUpdaterTest.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.content.pm;
-
-import static android.content.pm.PackageBuilder.builder;
-import static android.content.pm.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY;
-
-import android.os.Build;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/**
- * Test for {@link OrgApacheHttpLegacyUpdater}
- */
-@SmallTest
-@RunWith(OptionalClassRunner.class)
-@OptionalClassRunner.OptionalClass("android.content.pm.OrgApacheHttpLegacyUpdater")
-public class OrgApacheHttpLegacyUpdaterTest extends PackageSharedLibraryUpdaterTest {
-
-    private static final String OTHER_LIBRARY = "other.library";
-
-    @Test
-    public void targeted_at_O() {
-        PackageBuilder before = builder()
-                .targetSdkVersion(Build.VERSION_CODES.O);
-
-        // Should add org.apache.http.legacy.
-        PackageBuilder after = builder()
-                .targetSdkVersion(Build.VERSION_CODES.O)
-                .requiredLibraries(ORG_APACHE_HTTP_LEGACY);
-
-        checkBackwardsCompatibility(before, after);
-    }
-
-    @Test
-    public void targeted_at_O_not_empty_usesLibraries() {
-        PackageBuilder before = builder()
-                .targetSdkVersion(Build.VERSION_CODES.O)
-                .requiredLibraries(OTHER_LIBRARY);
-
-        // The org.apache.http.legacy jar should be added at the start of the list because it
-        // is not on the bootclasspath and the package targets pre-P.
-        PackageBuilder after = builder()
-                .targetSdkVersion(Build.VERSION_CODES.O)
-                .requiredLibraries(ORG_APACHE_HTTP_LEGACY, OTHER_LIBRARY);
-
-        checkBackwardsCompatibility(before, after);
-    }
-
-    @Test
-    public void targeted_at_O_in_usesLibraries() {
-        PackageBuilder before = builder()
-                .targetSdkVersion(Build.VERSION_CODES.O)
-                .requiredLibraries(ORG_APACHE_HTTP_LEGACY);
-
-        // No change is required because although org.apache.http.legacy has been removed from
-        // the bootclasspath the package explicitly requests it.
-        checkBackwardsCompatibility(before, before);
-    }
-
-    @Test
-    public void targeted_at_O_in_usesOptionalLibraries() {
-        PackageBuilder before = builder()
-                .targetSdkVersion(Build.VERSION_CODES.O)
-                .optionalLibraries(ORG_APACHE_HTTP_LEGACY);
-
-        // No change is required because although org.apache.http.legacy has been removed from
-        // the bootclasspath the package explicitly requests it.
-        checkBackwardsCompatibility(before, before);
-    }
-
-    @Test
-    public void in_usesLibraries() {
-        PackageBuilder before = builder().requiredLibraries(ORG_APACHE_HTTP_LEGACY);
-
-        // No change is required because the package explicitly requests org.apache.http.legacy
-        // and is targeted at the current version so does not need backwards compatibility.
-        checkBackwardsCompatibility(before, before);
-    }
-
-    @Test
-    public void in_usesOptionalLibraries() {
-        PackageBuilder before = builder().optionalLibraries(ORG_APACHE_HTTP_LEGACY);
-
-        // No change is required because the package explicitly requests org.apache.http.legacy
-        // and is targeted at the current version so does not need backwards compatibility.
-        checkBackwardsCompatibility(before, before);
-    }
-
-    private void checkBackwardsCompatibility(PackageBuilder before, PackageBuilder after) {
-        checkBackwardsCompatibility(before, after, OrgApacheHttpLegacyUpdater::new);
-    }
-}
diff --git a/core/tests/coretests/src/android/content/pm/PackageBackwardCompatibilityTest.java b/core/tests/coretests/src/android/content/pm/PackageBackwardCompatibilityTest.java
deleted file mode 100644
index ad9814b..0000000
--- a/core/tests/coretests/src/android/content/pm/PackageBackwardCompatibilityTest.java
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.content.pm;
-
-import static android.content.pm.PackageBuilder.builder;
-import static android.content.pm.SharedLibraryNames.ANDROID_TEST_BASE;
-import static android.content.pm.SharedLibraryNames.ANDROID_TEST_MOCK;
-import static android.content.pm.SharedLibraryNames.ANDROID_TEST_RUNNER;
-import static android.content.pm.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY;
-
-import android.content.pm.PackageBackwardCompatibility.RemoveUnnecessaryAndroidTestBaseLibrary;
-import android.os.Build;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.Assume;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-import java.util.ArrayList;
-import java.util.List;
-
-@SmallTest
-@RunWith(JUnit4.class)
-public class PackageBackwardCompatibilityTest extends PackageSharedLibraryUpdaterTest {
-
-    @Test
-    public void null_usesLibraries_and_usesOptionalLibraries() {
-        PackageBuilder before = builder();
-        PackageBuilder after = builder();
-
-        checkBackwardsCompatibility(before, after);
-    }
-
-    /**
-     * Detect when the android.test.base is not on the bootclasspath.
-     *
-     * <p>This test will be ignored when org.apache.http.legacy is not on the bootclasspath and
-     * succeed otherwise. This allows a developer to ensure that the tests are being run in the
-     * correct environment.
-     */
-    @Test
-    public void detectWhenATBisOnBCP() {
-        Assume.assumeTrue(PackageBackwardCompatibility.bootClassPathContainsATB());
-    }
-
-    /**
-     * Ensures that the {@link PackageBackwardCompatibility} uses {@link OrgApacheHttpLegacyUpdater}
-     * and {@link AndroidTestBaseUpdater} when necessary.
-     *
-     * <p>More comprehensive tests for that class can be found in
-     * {@link OrgApacheHttpLegacyUpdaterTest}.
-     */
-    @Test
-    public void targeted_at_O() {
-        PackageBuilder before = builder()
-                .targetSdkVersion(Build.VERSION_CODES.O);
-
-        List<String> expected = new ArrayList<>();
-        if (!PackageBackwardCompatibility.bootClassPathContainsATB()) {
-            expected.add(ANDROID_TEST_BASE);
-        }
-        expected.add(ORG_APACHE_HTTP_LEGACY);
-
-        PackageBuilder after = builder()
-                .targetSdkVersion(Build.VERSION_CODES.O)
-                .requiredLibraries(expected);
-
-        checkBackwardsCompatibility(before, after);
-    }
-
-    /**
-     * Ensures that the {@link PackageBackwardCompatibility} uses
-     * {@link RemoveUnnecessaryAndroidTestBaseLibrary}
-     * when necessary.
-     *
-     * <p>More comprehensive tests for that class can be found in
-     * {@link RemoveUnnecessaryAndroidTestBaseLibraryTest}.
-     */
-    @Test
-    public void android_test_base_in_usesLibraries() {
-        Assume.assumeTrue("Test requires that "
-                        + ANDROID_TEST_BASE + " is on the bootclasspath",
-                PackageBackwardCompatibility.bootClassPathContainsATB());
-
-        PackageBuilder before = builder()
-                .requiredLibraries(ANDROID_TEST_BASE);
-
-        // android.test.base should be removed from the libraries because it is provided
-        // on the bootclasspath and providing both increases start up cost unnecessarily.
-        PackageBuilder after = builder();
-
-        checkBackwardsCompatibility(before, after);
-    }
-
-    /**
-     * Ensures that the {@link PackageBackwardCompatibility} uses a
-     * {@link PackageBackwardCompatibility.AndroidTestRunnerSplitUpdater}.
-     *
-     * <p>More comprehensive tests for that class can be found in
-     * {@link AndroidTestRunnerSplitUpdaterTest}.
-     */
-    @Test
-    public void android_test_runner_in_usesLibraries() {
-        PackageBuilder before = builder().requiredLibraries(ANDROID_TEST_RUNNER);
-
-        List<String> expected = new ArrayList<>();
-        if (!PackageBackwardCompatibility.bootClassPathContainsATB()) {
-            expected.add(ANDROID_TEST_BASE);
-        }
-        expected.add(ANDROID_TEST_MOCK);
-        expected.add(ANDROID_TEST_RUNNER);
-
-        PackageBuilder after = builder()
-                .requiredLibraries(expected);
-
-        checkBackwardsCompatibility(before, after);
-    }
-
-    private void checkBackwardsCompatibility(PackageBuilder before, PackageBuilder after) {
-        checkBackwardsCompatibility(before, after, PackageBackwardCompatibility::getInstance);
-    }
-}
diff --git a/core/tests/coretests/src/android/content/pm/PackageBuilder.java b/core/tests/coretests/src/android/content/pm/PackageBuilder.java
deleted file mode 100644
index f7544af..0000000
--- a/core/tests/coretests/src/android/content/pm/PackageBuilder.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.content.pm;
-
-import static org.junit.Assert.assertEquals;
-
-import android.os.Build;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Test support for building {@link PackageParser.Package} instances.
- */
-class PackageBuilder {
-
-    private int mTargetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT;
-
-    private int mFlags = 0;
-
-    private ArrayList<String> mRequiredLibraries;
-
-    private ArrayList<String> mOptionalLibraries;
-
-    public static PackageBuilder builder() {
-        return new PackageBuilder();
-    }
-
-    public PackageParser.Package build() {
-        PackageParser.Package pkg = new PackageParser.Package("org.package.name");
-        pkg.applicationInfo.targetSdkVersion = mTargetSdkVersion;
-        pkg.applicationInfo.flags = mFlags;
-        pkg.usesLibraries = mRequiredLibraries;
-        pkg.usesOptionalLibraries = mOptionalLibraries;
-        return pkg;
-    }
-
-    PackageBuilder targetSdkVersion(int version) {
-        this.mTargetSdkVersion = version;
-        return this;
-    }
-
-    PackageBuilder asSystemApp() {
-        this.mFlags |= ApplicationInfo.FLAG_SYSTEM;
-        return this;
-    }
-
-    PackageBuilder requiredLibraries(String... names) {
-        this.mRequiredLibraries = arrayListOrNull(names);
-        return this;
-    }
-
-    PackageBuilder requiredLibraries(List<String> names) {
-        this.mRequiredLibraries = arrayListOrNull(names.toArray(new String[names.size()]));
-        return this;
-    }
-
-    PackageBuilder optionalLibraries(String... names) {
-        this.mOptionalLibraries = arrayListOrNull(names);
-        return this;
-    }
-
-    /**
-     * Check that this matches the supplied {@link PackageParser.Package}.
-     *
-     * @param pkg the instance to compare with this.
-     */
-    public void check(PackageParser.Package pkg) {
-        assertEquals("targetSdkVersion should not be changed",
-                mTargetSdkVersion,
-                pkg.applicationInfo.targetSdkVersion);
-        assertEquals("usesLibraries not updated correctly",
-                mRequiredLibraries,
-                pkg.usesLibraries);
-        assertEquals("usesOptionalLibraries not updated correctly",
-                mOptionalLibraries,
-                pkg.usesOptionalLibraries);
-    }
-
-    private static ArrayList<String> arrayListOrNull(String... strings) {
-        if (strings == null || strings.length == 0) {
-            return null;
-        }
-        ArrayList<String> list = new ArrayList<>();
-        Collections.addAll(list, strings);
-        return list;
-    }
-
-}
diff --git a/core/tests/coretests/src/android/content/pm/PackageParserTest.java b/core/tests/coretests/src/android/content/pm/PackageParserTest.java
index 5c7f2af..cb23850 100644
--- a/core/tests/coretests/src/android/content/pm/PackageParserTest.java
+++ b/core/tests/coretests/src/android/content/pm/PackageParserTest.java
@@ -23,26 +23,26 @@
 
 import android.apex.ApexInfo;
 import android.content.Context;
-import android.content.pm.PackageParser.Component;
-import android.content.pm.PackageParser.Package;
-import android.content.pm.PackageParser.Permission;
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.ComponentParseUtils.ParsedComponent;
+import android.content.pm.parsing.ComponentParseUtils.ParsedPermission;
+import android.content.pm.parsing.ParsedPackage;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.FileUtils;
-import android.os.SystemProperties;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.frameworks.coretests.R;
+import com.android.internal.util.ArrayUtils;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 import java.io.File;
 import java.io.InputStream;
-import java.util.Arrays;
 import java.util.function.Function;
 
 @SmallTest
@@ -59,8 +59,8 @@
     private static final String PRE_RELEASE_WITH_FINGERPRINT = "B.fingerprint";
     private static final String NEWER_PRE_RELEASE_WITH_FINGERPRINT = "C.fingerprint";
 
-    private static final String[] CODENAMES_RELEASED = { /* empty */ };
-    private static final String[] CODENAMES_PRE_RELEASE = { PRE_RELEASE };
+    private static final String[] CODENAMES_RELEASED = { /* empty */};
+    private static final String[] CODENAMES_PRE_RELEASE = {PRE_RELEASE};
 
     private static final int OLDER_VERSION = 10;
     private static final int PLATFORM_VERSION = 20;
@@ -300,10 +300,6 @@
         assertEquals(0x0083, finalConfigChanges); // Should be 10000011.
     }
 
-    Package parsePackage(String apkFileName, int apkResourceId) throws Exception {
-        return parsePackage(apkFileName, apkResourceId, p -> p);
-    }
-
     /**
      * Copies a specified {@code resourceId} to a file. Returns a non-null file if the copy
      * succeeded, or {@code null} otherwise.
@@ -331,16 +327,17 @@
      *
      * APKs are put into coretests/apks/packageparser_*.
      *
-     * @param apkFileName temporary file name to store apk extracted from resources
+     * @param apkFileName   temporary file name to store apk extracted from resources
      * @param apkResourceId identifier of the apk as a resource
      */
-    Package parsePackage(String apkFileName, int apkResourceId,
-            Function<Package, Package> converter) throws Exception {
+    ParsedPackage parsePackage(String apkFileName, int apkResourceId,
+            Function<ParsedPackage, ParsedPackage> converter) throws Exception {
         // Copy the resource to a file.
         File outFile = null;
         try {
             outFile = copyRawResourceToFile(apkFileName, apkResourceId);
-            return converter.apply(new PackageParser().parsePackage(outFile, 0 /* flags */));
+            return converter.apply(
+                    new PackageParser().parseParsedPackage(outFile, 0 /* flags */, false));
         } finally {
             if (outFile != null) {
                 outFile.delete();
@@ -351,40 +348,40 @@
     /**
      * Asserts basic properties about a component.
      */
-    private void assertComponent(String className, String packageName, int numIntents,
-            Component<?> component) {
+    private void assertComponent(String className, int numIntents, ParsedComponent<?> component) {
         assertEquals(className, component.className);
-        assertEquals(packageName, component.owner.packageName);
         assertEquals(numIntents, component.intents.size());
     }
 
     /**
      * Asserts four regularly-named components of each type: one Activity, one Service, one
      * Provider, and one Receiver.
+     *
      * @param template templated string with %s subbed with Activity, Service, Provider, Receiver
      */
-    private void assertOneComponentOfEachType(String template, Package p) {
-        String packageName = p.packageName;
+    private void assertOneComponentOfEachType(String template, AndroidPackage p) {
+        assertEquals(2, p.getActivities().size());
 
-        assertEquals(1, p.activities.size());
+        // For normal apps, a Activity that forwards to the App Details page is added.
+        assertEquals("android.app.AppDetailsActivity", p.getActivities().get(1)
+                .className);
+
         assertComponent(String.format(template, "Activity"),
-                packageName, 0 /* intents */, p.activities.get(0));
-        assertEquals(1, p.services.size());
+                0 /* intents */, p.getActivities().get(0));
+        assertEquals(1, p.getServices().size());
         assertComponent(String.format(template, "Service"),
-                packageName, 0 /* intents */, p.services.get(0));
-        assertEquals(1, p.providers.size());
+                0 /* intents */, p.getServices().get(0));
+        assertEquals(1, p.getProviders().size());
         assertComponent(String.format(template, "Provider"),
-                packageName, 0 /* intents */, p.providers.get(0));
-        assertEquals(1, p.receivers.size());
+                0 /* intents */, p.getProviders().get(0));
+        assertEquals(1, p.getReceivers().size());
         assertComponent(String.format(template, "Receiver"),
-                packageName, 0 /* intents */, p.receivers.get(0));
+                0 /* intents */, p.getReceivers().get(0));
     }
 
-    private void assertPermission(String name, String packageName, int protectionLevel,
-            Permission permission) {
-        assertEquals(packageName, permission.owner.packageName);
-        assertEquals(name, permission.info.name);
-        assertEquals(protectionLevel, permission.info.protectionLevel);
+    private void assertPermission(String name, int protectionLevel, ParsedPermission permission) {
+        assertEquals(name, permission.getName());
+        assertEquals(protectionLevel, permission.getProtection());
     }
 
     private void assertMetadata(Bundle b, String... keysAndValues) {
@@ -416,25 +413,25 @@
     }
 
     private void checkPackageWithComponents(
-            Function<Package, Package> converter) throws Exception {
-        Package p = parsePackage(
+            Function<ParsedPackage, ParsedPackage> converter) throws Exception {
+        ParsedPackage p = parsePackage(
                 "install_complete_package_info.apk", R.raw.install_complete_package_info,
                 converter);
         String packageName = "com.android.frameworks.coretests.install_complete_package_info";
 
-        assertEquals(packageName, p.packageName);
-        assertEquals(1, p.permissions.size());
+        assertEquals(packageName, p.getPackageName());
+        assertEquals(1, p.getPermissions().size());
         assertPermission(
                 "com.android.frameworks.coretests.install_complete_package_info.test_permission",
-                packageName, PermissionInfo.PROTECTION_NORMAL, p.permissions.get(0));
+                PermissionInfo.PROTECTION_NORMAL, p.getPermissions().get(0));
 
         // Hidden "app details" activity is added to every package.
         boolean foundAppDetailsActivity = false;
-        for (int i = 0; i < p.activities.size(); i++) {
-            if (p.activities.get(i).className.equals(
+        for (int i = 0; i < ArrayUtils.size(p.getActivities()); i++) {
+            if (p.getActivities().get(i).className.equals(
                     PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME)) {
                 foundAppDetailsActivity = true;
-                p.activities.remove(i);
+                p.getActivities().remove(i);
                 break;
             }
         }
@@ -442,72 +439,23 @@
 
         assertOneComponentOfEachType("com.android.frameworks.coretests.Test%s", p);
 
-        assertMetadata(p.mAppMetaData,
+        assertMetadata(p.getAppMetaData(),
                 "key1", "value1",
                 "key2", "this_is_app");
-        assertMetadata(p.activities.get(0).metaData,
+        assertMetadata(p.getActivities().get(0).getMetaData(),
                 "key1", "value1",
                 "key2", "this_is_activity");
-        assertMetadata(p.services.get(0).metaData,
+        assertMetadata(p.getServices().get(0).getMetaData(),
                 "key1", "value1",
                 "key2", "this_is_service");
-        assertMetadata(p.receivers.get(0).metaData,
+        assertMetadata(p.getReceivers().get(0).getMetaData(),
                 "key1", "value1",
                 "key2", "this_is_receiver");
-        assertMetadata(p.providers.get(0).metaData,
+        assertMetadata(p.getProviders().get(0).getMetaData(),
                 "key1", "value1",
                 "key2", "this_is_provider");
     }
 
-    /**
-     * Determines if the current device supports multi-package APKs.
-     */
-    private boolean supportsMultiPackageApk() {
-        return SystemProperties.getBoolean("persist.sys.child_packages_enabled", false);
-    }
-
-    @Test
-    public void testMultiPackageComponents() throws Exception {
-        // TODO(gboyer): Remove once we decide to launch multi-package APKs.
-        if (!supportsMultiPackageApk()) {
-            return;
-        }
-        String parentName = "com.android.frameworks.coretests.install_multi_package";
-        String firstChildName =
-                "com.android.frameworks.coretests.install_multi_package.first_child";
-        String secondChildName =  // NOTE: intentionally inconsistent!
-                "com.android.frameworks.coretests.blah.second_child";
-
-        Package parent = parsePackage("install_multi_package.apk", R.raw.install_multi_package);
-        assertEquals(parentName, parent.packageName);
-        assertEquals(2, parent.childPackages.size());
-        assertOneComponentOfEachType("com.android.frameworks.coretests.Test%s", parent);
-        assertEquals(1, parent.permissions.size());
-        assertPermission(parentName + ".test_permission", parentName,
-                PermissionInfo.PROTECTION_NORMAL, parent.permissions.get(0));
-        assertEquals(Arrays.asList("android.permission.INTERNET"),
-                parent.requestedPermissions);
-
-        Package firstChild = parent.childPackages.get(0);
-        assertEquals(firstChildName, firstChild.packageName);
-        assertOneComponentOfEachType(
-                "com.android.frameworks.coretests.FirstChildTest%s", firstChild);
-        assertEquals(0, firstChild.permissions.size());  // Child APKs cannot declare permissions.
-        assertEquals(Arrays.asList("android.permission.NFC"),
-                firstChild.requestedPermissions);
-
-        Package secondChild = parent.childPackages.get(1);
-        assertEquals(secondChildName, secondChild.packageName);
-        assertOneComponentOfEachType(
-                "com.android.frameworks.coretests.SecondChildTest%s", secondChild);
-        assertEquals(0, secondChild.permissions.size());  // Child APKs cannot declare permissions.
-        assertEquals(
-                Arrays.asList(
-                        "android.permission.ACCESS_NETWORK_STATE",
-                        "android.permission.READ_CONTACTS"),
-                secondChild.requestedPermissions);
-    }
-
     @Test
     public void testApexPackageInfoGeneration() throws Exception {
         String apexModuleName = "com.android.tzdata.apex";
@@ -522,7 +470,7 @@
         int flags = PackageManager.GET_META_DATA | PackageManager.GET_SIGNING_CERTIFICATES;
 
         PackageParser pp = new PackageParser();
-        Package p = pp.parsePackage(apexFile, flags, false);
+        PackageParser.Package p = pp.parsePackage(apexFile, flags, false);
         PackageParser.collectCertificates(p, false);
         PackageInfo pi = PackageParser.generatePackageInfo(p, apexInfo, flags);
 
diff --git a/core/tests/coretests/src/android/content/pm/PackageSharedLibraryUpdaterTest.java b/core/tests/coretests/src/android/content/pm/PackageSharedLibraryUpdaterTest.java
deleted file mode 100644
index 71a0e5e..0000000
--- a/core/tests/coretests/src/android/content/pm/PackageSharedLibraryUpdaterTest.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.content.pm;
-
-import java.util.function.Supplier;
-
-/**
- * Helper for classes that test {@link PackageSharedLibraryUpdater}.
- */
-abstract class PackageSharedLibraryUpdaterTest {
-
-    static void checkBackwardsCompatibility(PackageBuilder before, PackageBuilder after,
-            Supplier<PackageSharedLibraryUpdater> updaterSupplier) {
-        PackageParser.Package pkg = before.build();
-        updaterSupplier.get().updatePackage(pkg);
-        after.check(pkg);
-    }
-}
diff --git a/core/tests/coretests/src/android/content/pm/RemoveUnnecessaryAndroidTestBaseLibraryTest.java b/core/tests/coretests/src/android/content/pm/RemoveUnnecessaryAndroidTestBaseLibraryTest.java
deleted file mode 100644
index 216b0c8..0000000
--- a/core/tests/coretests/src/android/content/pm/RemoveUnnecessaryAndroidTestBaseLibraryTest.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.content.pm;
-
-import static android.content.pm.PackageBuilder.builder;
-import static android.content.pm.SharedLibraryNames.ANDROID_TEST_BASE;
-
-import android.content.pm.PackageBackwardCompatibility.RemoveUnnecessaryAndroidTestBaseLibrary;
-import android.os.Build;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/**
- * Test for {@link RemoveUnnecessaryAndroidTestBaseLibrary}
- */
-@SmallTest
-@RunWith(JUnit4.class)
-public class RemoveUnnecessaryAndroidTestBaseLibraryTest
-        extends PackageSharedLibraryUpdaterTest {
-
-    private static final String OTHER_LIBRARY = "other.library";
-
-    @Test
-    public void targeted_at_O() {
-        PackageBuilder before = builder()
-                .targetSdkVersion(Build.VERSION_CODES.O);
-
-        // No change required.
-        checkBackwardsCompatibility(before, before);
-    }
-
-    @Test
-    public void targeted_at_O_not_empty_usesLibraries() {
-        PackageBuilder before = builder()
-                .targetSdkVersion(Build.VERSION_CODES.O)
-                .requiredLibraries(OTHER_LIBRARY);
-
-        // No change required.
-        checkBackwardsCompatibility(before, before);
-    }
-
-    @Test
-    public void targeted_at_O_in_usesLibraries() {
-        PackageBuilder before = builder()
-                .targetSdkVersion(Build.VERSION_CODES.O)
-                .requiredLibraries(ANDROID_TEST_BASE);
-
-        // android.test.base should be removed from the libraries because it is provided
-        // on the bootclasspath and providing both increases start up cost unnecessarily.
-        PackageBuilder after = builder()
-                .targetSdkVersion(Build.VERSION_CODES.O);
-
-        checkBackwardsCompatibility(before, after);
-    }
-
-    @Test
-    public void targeted_at_O_in_usesOptionalLibraries() {
-        PackageBuilder before = builder()
-                .targetSdkVersion(Build.VERSION_CODES.O)
-                .optionalLibraries(ANDROID_TEST_BASE);
-
-        // android.test.base should be removed from the libraries because it is provided
-        // on the bootclasspath and providing both increases start up cost unnecessarily.
-        PackageBuilder after = builder()
-                .targetSdkVersion(Build.VERSION_CODES.O);
-
-        checkBackwardsCompatibility(before, after);
-    }
-
-    @Test
-    public void in_usesLibraries() {
-        PackageBuilder before = builder().requiredLibraries(ANDROID_TEST_BASE);
-
-        // android.test.base should be removed from the libraries because it is provided
-        // on the bootclasspath and providing both increases start up cost unnecessarily.
-        PackageBuilder after = builder();
-
-        checkBackwardsCompatibility(before, after);
-    }
-
-    @Test
-    public void in_usesOptionalLibraries() {
-        PackageBuilder before = builder().optionalLibraries(ANDROID_TEST_BASE);
-
-        // android.test.base should be removed from the libraries because it is provided
-        // on the bootclasspath and providing both increases start up cost unnecessarily.
-        PackageBuilder after = builder();
-
-        checkBackwardsCompatibility(before, after);
-    }
-
-    @Test
-    public void in_bothLibraries() {
-        PackageBuilder before = builder()
-                .requiredLibraries(ANDROID_TEST_BASE)
-                .optionalLibraries(ANDROID_TEST_BASE);
-
-        // android.test.base should be removed from the libraries because it is provided
-        // on the bootclasspath and providing both increases start up cost unnecessarily.
-        PackageBuilder after = builder();
-
-        checkBackwardsCompatibility(before, after);
-    }
-
-    private void checkBackwardsCompatibility(PackageBuilder before, PackageBuilder after) {
-        // TODO(b/72538146) - Cannot use constructor reference here because it is also used in
-        // PackageBackwardCompatibility and that seems to create a package-private lambda in
-        // android.content.pm which this then tries to reuse but fails because it cannot access
-        // package-private classes/members because the test is loaded by a different ClassLoader
-        // than the lambda.
-        checkBackwardsCompatibility(before, after,
-                () -> new RemoveUnnecessaryAndroidTestBaseLibrary());
-    }
-
-}
diff --git a/core/tests/coretests/src/android/content/pm/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java b/core/tests/coretests/src/android/content/pm/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java
deleted file mode 100644
index fc60980..0000000
--- a/core/tests/coretests/src/android/content/pm/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.content.pm;
-
-import static android.content.pm.PackageBuilder.builder;
-import static android.content.pm.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY;
-
-import android.content.pm.PackageBackwardCompatibility.RemoveUnnecessaryOrgApacheHttpLegacyLibrary;
-import android.os.Build;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/**
- * Test for {@link RemoveUnnecessaryOrgApacheHttpLegacyLibrary}
- */
-@SmallTest
-@RunWith(JUnit4.class)
-public class RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest
-        extends PackageSharedLibraryUpdaterTest {
-
-    private static final String OTHER_LIBRARY = "other.library";
-
-    @Test
-    public void targeted_at_O() {
-        PackageBuilder before = builder()
-                .targetSdkVersion(Build.VERSION_CODES.O);
-
-        // No change required.
-        checkBackwardsCompatibility(before, before);
-    }
-
-    @Test
-    public void targeted_at_O_not_empty_usesLibraries() {
-        PackageBuilder before = builder()
-                .targetSdkVersion(Build.VERSION_CODES.O)
-                .requiredLibraries(OTHER_LIBRARY);
-
-        // No change required.
-        checkBackwardsCompatibility(before, before);
-    }
-
-    @Test
-    public void targeted_at_O_in_usesLibraries() {
-        PackageBuilder before = builder()
-                .targetSdkVersion(Build.VERSION_CODES.O)
-                .requiredLibraries(ORG_APACHE_HTTP_LEGACY);
-
-        // org.apache.http.legacy should be removed from the libraries because it is provided
-        // on the bootclasspath and providing both increases start up cost unnecessarily.
-        PackageBuilder after = builder()
-                .targetSdkVersion(Build.VERSION_CODES.O);
-
-        checkBackwardsCompatibility(before, after);
-    }
-
-    @Test
-    public void targeted_at_O_in_usesOptionalLibraries() {
-        PackageBuilder before = builder()
-                .targetSdkVersion(Build.VERSION_CODES.O)
-                .optionalLibraries(ORG_APACHE_HTTP_LEGACY);
-
-        // org.apache.http.legacy should be removed from the libraries because it is provided
-        // on the bootclasspath and providing both increases start up cost unnecessarily.
-        PackageBuilder after = builder()
-                .targetSdkVersion(Build.VERSION_CODES.O);
-
-        checkBackwardsCompatibility(before, after);
-    }
-
-    @Test
-    public void in_usesLibraries() {
-        PackageBuilder before = builder().requiredLibraries(ORG_APACHE_HTTP_LEGACY);
-
-        // org.apache.http.legacy should be removed from the libraries because it is provided
-        // on the bootclasspath and providing both increases start up cost unnecessarily.
-        PackageBuilder after = builder();
-
-        checkBackwardsCompatibility(before, after);
-    }
-
-    @Test
-    public void in_usesOptionalLibraries() {
-        PackageBuilder before = builder().optionalLibraries(ORG_APACHE_HTTP_LEGACY);
-
-        // org.apache.http.legacy should be removed from the libraries because it is provided
-        // on the bootclasspath and providing both increases start up cost unnecessarily.
-        PackageBuilder after = builder();
-
-        checkBackwardsCompatibility(before, after);
-    }
-
-    @Test
-    public void in_bothLibraries() {
-        PackageBuilder before = builder()
-                .requiredLibraries(ORG_APACHE_HTTP_LEGACY)
-                .optionalLibraries(ORG_APACHE_HTTP_LEGACY);
-
-        // org.apache.http.legacy should be removed from the libraries because it is provided
-        // on the bootclasspath and providing both increases start up cost unnecessarily.
-        PackageBuilder after = builder();
-
-        checkBackwardsCompatibility(before, after);
-    }
-
-    private void checkBackwardsCompatibility(PackageBuilder before, PackageBuilder after) {
-        // TODO(b/72538146) - Cannot use constructor reference here because it is also used in
-        // PackageBackwardCompatibility and that seems to create a package-private lambda in
-        // android.content.pm which this then tries to reuse but fails because it cannot access
-        // package-private classes/members because the test is loaded by a different ClassLoader
-        // than the lambda.
-        checkBackwardsCompatibility(before, after,
-                () -> new RemoveUnnecessaryOrgApacheHttpLegacyLibrary());
-    }
-}
diff --git a/core/tests/coretests/src/android/content/pm/dex/DexMetadataHelperTest.java b/core/tests/coretests/src/android/content/pm/dex/DexMetadataHelperTest.java
index 49849ee..1e0bfb0 100644
--- a/core/tests/coretests/src/android/content/pm/dex/DexMetadataHelperTest.java
+++ b/core/tests/coretests/src/android/content/pm/dex/DexMetadataHelperTest.java
@@ -25,9 +25,9 @@
 import android.content.pm.PackageManager;
 import android.content.pm.PackageParser;
 import android.content.pm.PackageParser.ApkLite;
-import android.content.pm.PackageParser.Package;
 import android.content.pm.PackageParser.PackageLite;
 import android.content.pm.PackageParser.PackageParserException;
+import android.content.pm.parsing.ParsedPackage;
 import android.os.FileUtils;
 
 import androidx.test.InstrumentationRegistry;
@@ -36,7 +36,6 @@
 
 import com.android.frameworks.coretests.R;
 
-import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Rule;
@@ -95,13 +94,13 @@
     public void testParsePackageWithDmFileValid() throws IOException, PackageParserException {
         copyApkToToTmpDir("install_split_base.apk", R.raw.install_split_base);
         createDexMetadataFile("install_split_base.apk");
-        Package pkg = new PackageParser().parsePackage(mTmpDir, 0 /* flags */);
+        ParsedPackage pkg = new PackageParser().parseParsedPackage(mTmpDir, 0 /* flags */, false);
 
         Map<String, String> packageDexMetadata = DexMetadataHelper.getPackageDexMetadata(pkg);
         assertEquals(1, packageDexMetadata.size());
-        String baseDexMetadata = packageDexMetadata.get(pkg.baseCodePath);
+        String baseDexMetadata = packageDexMetadata.get(pkg.getBaseCodePath());
         assertNotNull(baseDexMetadata);
-        assertTrue(isDexMetadataForApk(baseDexMetadata, pkg.baseCodePath));
+        assertTrue(isDexMetadataForApk(baseDexMetadata, pkg.getBaseCodePath()));
     }
 
     @Test
@@ -111,17 +110,17 @@
         copyApkToToTmpDir("install_split_feature_a.apk", R.raw.install_split_feature_a);
         createDexMetadataFile("install_split_base.apk");
         createDexMetadataFile("install_split_feature_a.apk");
-        Package pkg = new PackageParser().parsePackage(mTmpDir, 0 /* flags */);
+        ParsedPackage pkg = new PackageParser().parseParsedPackage(mTmpDir, 0 /* flags */, false);
 
         Map<String, String> packageDexMetadata = DexMetadataHelper.getPackageDexMetadata(pkg);
         assertEquals(2, packageDexMetadata.size());
-        String baseDexMetadata = packageDexMetadata.get(pkg.baseCodePath);
+        String baseDexMetadata = packageDexMetadata.get(pkg.getBaseCodePath());
         assertNotNull(baseDexMetadata);
-        assertTrue(isDexMetadataForApk(baseDexMetadata, pkg.baseCodePath));
+        assertTrue(isDexMetadataForApk(baseDexMetadata, pkg.getBaseCodePath()));
 
-        String splitDexMetadata = packageDexMetadata.get(pkg.splitCodePaths[0]);
+        String splitDexMetadata = packageDexMetadata.get(pkg.getSplitCodePaths()[0]);
         assertNotNull(splitDexMetadata);
-        assertTrue(isDexMetadataForApk(splitDexMetadata, pkg.splitCodePaths[0]));
+        assertTrue(isDexMetadataForApk(splitDexMetadata, pkg.getSplitCodePaths()[0]));
     }
 
     @Test
@@ -130,14 +129,14 @@
         copyApkToToTmpDir("install_split_base.apk", R.raw.install_split_base);
         copyApkToToTmpDir("install_split_feature_a.apk", R.raw.install_split_feature_a);
         createDexMetadataFile("install_split_feature_a.apk");
-        Package pkg = new PackageParser().parsePackage(mTmpDir, 0 /* flags */);
+        ParsedPackage pkg = new PackageParser().parseParsedPackage(mTmpDir, 0 /* flags */, false);
 
         Map<String, String> packageDexMetadata = DexMetadataHelper.getPackageDexMetadata(pkg);
         assertEquals(1, packageDexMetadata.size());
 
-        String splitDexMetadata = packageDexMetadata.get(pkg.splitCodePaths[0]);
+        String splitDexMetadata = packageDexMetadata.get(pkg.getSplitCodePaths()[0]);
         assertNotNull(splitDexMetadata);
-        assertTrue(isDexMetadataForApk(splitDexMetadata, pkg.splitCodePaths[0]));
+        assertTrue(isDexMetadataForApk(splitDexMetadata, pkg.getSplitCodePaths()[0]));
     }
 
     @Test
@@ -146,7 +145,8 @@
         File invalidDmFile = new File(mTmpDir, "install_split_base.dm");
         Files.createFile(invalidDmFile.toPath());
         try {
-            PackageParser.Package pkg = new PackageParser().parsePackage(mTmpDir, 0 /* flags */);
+            ParsedPackage pkg = new PackageParser()
+                    .parseParsedPackage(mTmpDir, 0 /* flags */, false);
             DexMetadataHelper.validatePackageDexMetadata(pkg);
         } catch (PackageParserException e) {
             assertEquals(e.error, PackageManager.INSTALL_FAILED_BAD_DEX_METADATA);
@@ -163,7 +163,8 @@
         Files.createFile(invalidDmFile.toPath());
 
         try {
-            PackageParser.Package pkg = new PackageParser().parsePackage(mTmpDir, 0 /* flags */);
+            ParsedPackage pkg = new PackageParser()
+                    .parseParsedPackage(mTmpDir, 0 /* flags */, false);
             DexMetadataHelper.validatePackageDexMetadata(pkg);
         } catch (PackageParserException e) {
             assertEquals(e.error, PackageManager.INSTALL_FAILED_BAD_DEX_METADATA);
diff --git a/core/tests/coretests/src/android/content/pm/parsing/library/AndroidHidlUpdaterTest.java b/core/tests/coretests/src/android/content/pm/parsing/library/AndroidHidlUpdaterTest.java
new file mode 100644
index 0000000..21479c0
--- /dev/null
+++ b/core/tests/coretests/src/android/content/pm/parsing/library/AndroidHidlUpdaterTest.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm.parsing.library;
+
+import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_HIDL_BASE;
+import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_HIDL_MANAGER;
+
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.PackageImpl;
+import android.content.pm.parsing.ParsedPackage;
+import android.os.Build;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Test for {@link AndroidHidlUpdater}
+ */
+@SmallTest
+@RunWith(JUnit4.class)
+public class AndroidHidlUpdaterTest extends PackageSharedLibraryUpdaterTest {
+
+    private static final String OTHER_LIBRARY = "other.library";
+
+    @Test
+    public void targeted_at_P() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.P)
+                .hideAsParsed();
+
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.P)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        // no change, not system
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void targeted_at_P_system() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.P)
+                .hideAsParsed()
+                .setSystem(true);
+
+        // Should add both HIDL libraries
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.P)
+                .addUsesLibrary(ANDROID_HIDL_MANAGER)
+                .addUsesLibrary(ANDROID_HIDL_BASE)
+                .hideAsParsed()
+                .setSystem(true)
+                .hideAsFinal();
+
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void targeted_at_P_not_empty_usesLibraries() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.P)
+                .addUsesLibrary(OTHER_LIBRARY)
+                .hideAsParsed();
+
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.P)
+                .addUsesLibrary(OTHER_LIBRARY)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        // no change, not system
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void targeted_at_P_not_empty_usesLibraries_system() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.P)
+                .addUsesLibrary(OTHER_LIBRARY)
+                .hideAsParsed()
+                .setSystem(true);
+
+        // The hidl jars should be added at the start of the list because it
+        // is not on the bootclasspath and the package targets pre-P.
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.P)
+                .addUsesLibrary(ANDROID_HIDL_MANAGER)
+                .addUsesLibrary(ANDROID_HIDL_BASE)
+                .addUsesLibrary(OTHER_LIBRARY)
+                .hideAsParsed()
+                .setSystem(true)
+                .hideAsFinal();
+
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void targeted_at_P_in_usesLibraries() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.P)
+                .addUsesLibrary(ANDROID_HIDL_MANAGER)
+                .addUsesLibrary(ANDROID_HIDL_BASE)
+                .hideAsParsed();
+
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.P)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        // Libraries are removed because they are not available for non-system apps
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void targeted_at_P_in_usesLibraries_system() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.P)
+                .addUsesLibrary(ANDROID_HIDL_MANAGER)
+                .addUsesLibrary(ANDROID_HIDL_BASE)
+                .hideAsParsed()
+                .setSystem(true);
+
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.P)
+                .addUsesLibrary(ANDROID_HIDL_MANAGER)
+                .addUsesLibrary(ANDROID_HIDL_BASE)
+                .hideAsParsed()
+                .setSystem(true)
+                .hideAsFinal();
+
+        // No change is required because the package explicitly requests the HIDL libraries
+        // and is targeted at the current version so does not need backwards compatibility.
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void in_usesLibraries() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+                .addUsesLibrary(ANDROID_HIDL_BASE)
+                .hideAsParsed();
+
+        // Dependency is removed, it is not available.
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        // Libraries are removed because they are not available for apps targeting Q+
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void in_usesOptionalLibraries() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+                .addUsesOptionalLibrary(ANDROID_HIDL_BASE)
+                .hideAsParsed();
+
+        // Dependency is removed, it is not available.
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        // Libraries are removed because they are not available for apps targeting Q+
+        checkBackwardsCompatibility(before, after);
+    }
+
+    private void checkBackwardsCompatibility(ParsedPackage before, AndroidPackage after) {
+        checkBackwardsCompatibility(before, after, AndroidHidlUpdater::new);
+    }
+}
diff --git a/core/tests/coretests/src/android/content/pm/parsing/library/AndroidTestBaseUpdaterTest.java b/core/tests/coretests/src/android/content/pm/parsing/library/AndroidTestBaseUpdaterTest.java
new file mode 100644
index 0000000..65ae219
--- /dev/null
+++ b/core/tests/coretests/src/android/content/pm/parsing/library/AndroidTestBaseUpdaterTest.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm.parsing.library;
+
+import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_BASE;
+
+import android.content.pm.OptionalClassRunner;
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.PackageImpl;
+import android.content.pm.parsing.ParsedPackage;
+import android.os.Build;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test for {@link AndroidTestBaseUpdater}
+ */
+@SmallTest
+@RunWith(OptionalClassRunner.class)
+@OptionalClassRunner.OptionalClass("android.content.pm.parsing.library.AndroidTestBaseUpdater")
+public class AndroidTestBaseUpdaterTest extends PackageSharedLibraryUpdaterTest {
+
+    private static final String OTHER_LIBRARY = "other.library";
+
+    @Test
+    public void targeted_at_Q() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.Q)
+                .hideAsParsed();
+
+        // Should add org.apache.http.legacy.
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.Q)
+                .addUsesLibrary(ANDROID_TEST_BASE)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void targeted_at_Q_not_empty_usesLibraries() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.Q)
+                .addUsesLibrary(OTHER_LIBRARY)
+                .hideAsParsed();
+
+        // The org.apache.http.legacy jar should be added at the start of the list because it
+        // is not on the bootclasspath and the package targets pre-Q.
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.Q)
+                .addUsesLibrary(ANDROID_TEST_BASE)
+                .addUsesLibrary(OTHER_LIBRARY)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void targeted_at_Q_in_usesLibraries() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.Q)
+                .addUsesLibrary(ANDROID_TEST_BASE)
+                .hideAsParsed();
+
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.Q)
+                .addUsesLibrary(ANDROID_TEST_BASE)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        // No change is required because although org.apache.http.legacy has been removed from
+        // the bootclasspath the package explicitly requests it.
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void targeted_at_Q_in_usesOptionalLibraries() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.Q)
+                .addUsesOptionalLibrary(ANDROID_TEST_BASE)
+                .hideAsParsed();
+
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.Q)
+                .addUsesOptionalLibrary(ANDROID_TEST_BASE)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        // No change is required because although org.apache.http.legacy has been removed from
+        // the bootclasspath the package explicitly requests it.
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void in_usesLibraries() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+                .addUsesLibrary(ANDROID_TEST_BASE)
+                .hideAsParsed();
+
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+                .addUsesLibrary(ANDROID_TEST_BASE)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        // No change is required because the package explicitly requests org.apache.http.legacy
+        // and is targeted at the current version so does not need backwards compatibility.
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void in_usesOptionalLibraries() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+                .addUsesOptionalLibrary(ANDROID_TEST_BASE)
+                .hideAsParsed();
+
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+                .addUsesOptionalLibrary(ANDROID_TEST_BASE)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        // No change is required because the package explicitly requests org.apache.http.legacy
+        // and is targeted at the current version so does not need backwards compatibility.
+        checkBackwardsCompatibility(before, after);
+    }
+
+    private void checkBackwardsCompatibility(ParsedPackage before, AndroidPackage after) {
+        checkBackwardsCompatibility(before, after, AndroidTestBaseUpdater::new);
+    }
+}
diff --git a/core/tests/coretests/src/android/content/pm/parsing/library/AndroidTestRunnerSplitUpdaterTest.java b/core/tests/coretests/src/android/content/pm/parsing/library/AndroidTestRunnerSplitUpdaterTest.java
new file mode 100644
index 0000000..38755b9
--- /dev/null
+++ b/core/tests/coretests/src/android/content/pm/parsing/library/AndroidTestRunnerSplitUpdaterTest.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm.parsing.library;
+
+import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_MOCK;
+import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_RUNNER;
+
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.PackageImpl;
+import android.content.pm.parsing.ParsedPackage;
+import android.content.pm.parsing.library.PackageBackwardCompatibility.AndroidTestRunnerSplitUpdater;
+import android.os.Build;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Test for {@link AndroidTestRunnerSplitUpdater}
+ */
+@SmallTest
+@RunWith(JUnit4.class)
+public class AndroidTestRunnerSplitUpdaterTest extends PackageSharedLibraryUpdaterTest {
+
+    @Test
+    public void android_test_runner_in_usesOptionalLibraries() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+                .addUsesOptionalLibrary(ANDROID_TEST_RUNNER)
+                .hideAsParsed();
+
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+                .addUsesOptionalLibrary(ANDROID_TEST_MOCK)
+                .addUsesOptionalLibrary(ANDROID_TEST_RUNNER)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void android_test_runner_in_usesLibraries_android_test_mock_in_usesOptionalLibraries() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+                .addUsesLibrary(ANDROID_TEST_RUNNER)
+                .addUsesOptionalLibrary(ANDROID_TEST_MOCK)
+                .hideAsParsed();
+
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+                .addUsesLibrary(ANDROID_TEST_RUNNER)
+                .addUsesOptionalLibrary(ANDROID_TEST_MOCK)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        checkBackwardsCompatibility(before, after);
+    }
+
+    private void checkBackwardsCompatibility(ParsedPackage before, AndroidPackage after) {
+        checkBackwardsCompatibility(before, after, AndroidTestRunnerSplitUpdater::new);
+    }
+}
diff --git a/core/tests/coretests/src/android/content/pm/parsing/library/OrgApacheHttpLegacyUpdaterTest.java b/core/tests/coretests/src/android/content/pm/parsing/library/OrgApacheHttpLegacyUpdaterTest.java
new file mode 100644
index 0000000..4c7899b
--- /dev/null
+++ b/core/tests/coretests/src/android/content/pm/parsing/library/OrgApacheHttpLegacyUpdaterTest.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm.parsing.library;
+
+import static android.content.pm.parsing.library.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY;
+
+import android.content.pm.OptionalClassRunner;
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.PackageImpl;
+import android.content.pm.parsing.ParsedPackage;
+import android.os.Build;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test for {@link OrgApacheHttpLegacyUpdater}
+ */
+@SmallTest
+@RunWith(OptionalClassRunner.class)
+@OptionalClassRunner.OptionalClass("android.content.pm.parsing.library.OrgApacheHttpLegacyUpdater")
+public class OrgApacheHttpLegacyUpdaterTest extends PackageSharedLibraryUpdaterTest {
+
+    private static final String OTHER_LIBRARY = "other.library";
+
+    @Test
+    public void targeted_at_O() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.O)
+                .hideAsParsed();
+
+        // Should add org.apache.http.legacy.
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.O)
+                .addUsesLibrary(ORG_APACHE_HTTP_LEGACY)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void targeted_at_O_not_empty_usesLibraries() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.O)
+                .addUsesLibrary(OTHER_LIBRARY)
+                .hideAsParsed();
+
+        // The org.apache.http.legacy jar should be added at the start of the list because it
+        // is not on the bootclasspath and the package targets pre-P.
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.O)
+                .addUsesLibrary(ORG_APACHE_HTTP_LEGACY)
+                .addUsesLibrary(OTHER_LIBRARY)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void targeted_at_O_in_usesLibraries() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.O)
+                .addUsesLibrary(ORG_APACHE_HTTP_LEGACY)
+                .hideAsParsed();
+
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.O)
+                .addUsesLibrary(ORG_APACHE_HTTP_LEGACY)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        // No change is required because although org.apache.http.legacy has been removed from
+        // the bootclasspath the package explicitly requests it.
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void targeted_at_O_in_usesOptionalLibraries() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.O)
+                .addUsesOptionalLibrary(ORG_APACHE_HTTP_LEGACY)
+                .hideAsParsed();
+
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.O)
+                .addUsesOptionalLibrary(ORG_APACHE_HTTP_LEGACY)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        // No change is required because although org.apache.http.legacy has been removed from
+        // the bootclasspath the package explicitly requests it.
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void in_usesLibraries() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+                .addUsesLibrary(ORG_APACHE_HTTP_LEGACY)
+                .hideAsParsed();
+
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+                .addUsesLibrary(ORG_APACHE_HTTP_LEGACY)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        // No change is required because the package explicitly requests org.apache.http.legacy
+        // and is targeted at the current version so does not need backwards compatibility.
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void in_usesOptionalLibraries() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+                .addUsesOptionalLibrary(ORG_APACHE_HTTP_LEGACY)
+                .hideAsParsed();
+
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+                .addUsesOptionalLibrary(ORG_APACHE_HTTP_LEGACY)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        // No change is required because the package explicitly requests org.apache.http.legacy
+        // and is targeted at the current version so does not need backwards compatibility.
+        checkBackwardsCompatibility(before, after);
+    }
+
+    private void checkBackwardsCompatibility(ParsedPackage before, AndroidPackage after) {
+        checkBackwardsCompatibility(before, after, OrgApacheHttpLegacyUpdater::new);
+    }
+}
diff --git a/core/tests/coretests/src/android/content/pm/parsing/library/PackageBackwardCompatibilityTest.java b/core/tests/coretests/src/android/content/pm/parsing/library/PackageBackwardCompatibilityTest.java
new file mode 100644
index 0000000..00d468d
--- /dev/null
+++ b/core/tests/coretests/src/android/content/pm/parsing/library/PackageBackwardCompatibilityTest.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm.parsing.library;
+
+import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_BASE;
+import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_MOCK;
+import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_RUNNER;
+import static android.content.pm.parsing.library.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY;
+
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.PackageImpl;
+import android.content.pm.parsing.ParsedPackage;
+import android.content.pm.parsing.ParsingPackage;
+import android.content.pm.parsing.library.PackageBackwardCompatibility.RemoveUnnecessaryAndroidTestBaseLibrary;
+import android.os.Build;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Assume;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@SmallTest
+@RunWith(JUnit4.class)
+public class PackageBackwardCompatibilityTest extends PackageSharedLibraryUpdaterTest {
+
+    @Test
+    public void null_usesLibraries_and_usesOptionalLibraries() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+                .hideAsParsed();
+
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        checkBackwardsCompatibility(before, after);
+    }
+
+    /**
+     * Detect when the android.test.base is not on the bootclasspath.
+     *
+     * <p>This test will be ignored when org.apache.http.legacy is not on the bootclasspath and
+     * succeed otherwise. This allows a developer to ensure that the tests are being run in the
+     * correct environment.
+     */
+    @Test
+    public void detectWhenATBisOnBCP() {
+        Assume.assumeTrue(PackageBackwardCompatibility.bootClassPathContainsATB());
+    }
+
+    /**
+     * Ensures that the {@link PackageBackwardCompatibility} uses {@link OrgApacheHttpLegacyUpdater}
+     * and {@link AndroidTestBaseUpdater} when necessary.
+     *
+     * <p>More comprehensive tests for that class can be found in
+     * {@link OrgApacheHttpLegacyUpdaterTest}.
+     */
+    @Test
+    public void targeted_at_O() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+                .setTargetSdkVersion(Build.VERSION_CODES.O)
+                .hideAsParsed();
+
+        ParsingPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+                .setTargetSdkVersion(Build.VERSION_CODES.O);
+
+        if (!PackageBackwardCompatibility.bootClassPathContainsATB()) {
+            after.addUsesLibrary(ANDROID_TEST_BASE);
+        }
+        after.addUsesLibrary(ORG_APACHE_HTTP_LEGACY);
+
+        checkBackwardsCompatibility(before, after.hideAsParsed().hideAsFinal());
+    }
+
+    /**
+     * Ensures that the {@link PackageBackwardCompatibility} uses
+     * {@link RemoveUnnecessaryAndroidTestBaseLibrary}
+     * when necessary.
+     *
+     * <p>More comprehensive tests for that class can be found in
+     * {@link RemoveUnnecessaryAndroidTestBaseLibraryTest}.
+     */
+    @Test
+    public void android_test_base_in_usesLibraries() {
+        Assume.assumeTrue("Test requires that "
+                        + ANDROID_TEST_BASE + " is on the bootclasspath",
+                PackageBackwardCompatibility.bootClassPathContainsATB());
+
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+                .addUsesLibrary(ANDROID_TEST_BASE)
+                .hideAsParsed();
+
+        // android.test.base should be removed from the libraries because it is provided
+        // on the bootclasspath and providing both increases start up cost unnecessarily.
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        checkBackwardsCompatibility(before, after);
+    }
+
+    /**
+     * Ensures that the {@link PackageBackwardCompatibility} uses a
+     * {@link PackageBackwardCompatibility.AndroidTestRunnerSplitUpdater}.
+     *
+     * <p>More comprehensive tests for that class can be found in
+     * {@link AndroidTestRunnerSplitUpdaterTest}.
+     */
+    @Test
+    public void android_test_runner_in_usesLibraries() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+                .addUsesLibrary(ANDROID_TEST_RUNNER)
+                .hideAsParsed();
+
+        ParsingPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT);
+        if (!PackageBackwardCompatibility.bootClassPathContainsATB()) {
+            after.addUsesLibrary(ANDROID_TEST_BASE);
+        }
+        after.addUsesLibrary(ANDROID_TEST_MOCK);
+        after.addUsesLibrary(ANDROID_TEST_RUNNER);
+
+        checkBackwardsCompatibility(before, after.hideAsParsed().hideAsFinal());
+    }
+
+    private void checkBackwardsCompatibility(ParsedPackage before, AndroidPackage after) {
+        checkBackwardsCompatibility(before, after, PackageBackwardCompatibility::getInstance);
+    }
+}
diff --git a/core/tests/coretests/src/android/content/pm/parsing/library/PackageSharedLibraryUpdaterTest.java b/core/tests/coretests/src/android/content/pm/parsing/library/PackageSharedLibraryUpdaterTest.java
new file mode 100644
index 0000000..e7a80e1a
--- /dev/null
+++ b/core/tests/coretests/src/android/content/pm/parsing/library/PackageSharedLibraryUpdaterTest.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm.parsing.library;
+
+import static org.junit.Assert.assertEquals;
+
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.ParsedPackage;
+
+import java.util.function.Supplier;
+
+/**
+ * Helper for classes that test {@link PackageSharedLibraryUpdater}.
+ */
+abstract class PackageSharedLibraryUpdaterTest {
+
+    protected static final String PACKAGE_NAME = "org.package.name";
+
+    static void checkBackwardsCompatibility(ParsedPackage before, AndroidPackage after,
+            Supplier<PackageSharedLibraryUpdater> updaterSupplier) {
+        updaterSupplier.get().updatePackage(before);
+        check(before.hideAsFinal(), after);
+    }
+
+    private static void check(AndroidPackage before, AndroidPackage after) {
+        assertEquals("targetSdkVersion should not be changed",
+                after.getTargetSdkVersion(),
+                before.getTargetSdkVersion());
+        assertEquals("usesLibraries not updated correctly",
+                after.getUsesLibraries(),
+                before.getUsesLibraries());
+        assertEquals("usesOptionalLibraries not updated correctly",
+                after.getUsesOptionalLibraries(),
+                before.getUsesOptionalLibraries());
+    }
+}
diff --git a/core/tests/coretests/src/android/content/pm/parsing/library/RemoveUnnecessaryAndroidTestBaseLibraryTest.java b/core/tests/coretests/src/android/content/pm/parsing/library/RemoveUnnecessaryAndroidTestBaseLibraryTest.java
new file mode 100644
index 0000000..fd3ba2b
--- /dev/null
+++ b/core/tests/coretests/src/android/content/pm/parsing/library/RemoveUnnecessaryAndroidTestBaseLibraryTest.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm.parsing.library;
+
+import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_BASE;
+
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.PackageImpl;
+import android.content.pm.parsing.ParsedPackage;
+import android.content.pm.parsing.library.PackageBackwardCompatibility.RemoveUnnecessaryAndroidTestBaseLibrary;
+import android.os.Build;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Test for {@link RemoveUnnecessaryAndroidTestBaseLibrary}
+ */
+@SmallTest
+@RunWith(JUnit4.class)
+public class RemoveUnnecessaryAndroidTestBaseLibraryTest
+        extends PackageSharedLibraryUpdaterTest {
+
+    private static final String OTHER_LIBRARY = "other.library";
+
+    @Test
+    public void targeted_at_O() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.O)
+                .hideAsParsed();
+
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.O)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        // No change required.
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void targeted_at_O_not_empty_usesLibraries() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.O)
+                .addUsesLibrary(OTHER_LIBRARY)
+                .hideAsParsed();
+
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.O)
+                .addUsesLibrary(OTHER_LIBRARY)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        // No change required.
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void targeted_at_O_in_usesLibraries() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.O)
+                .addUsesLibrary(ANDROID_TEST_BASE)
+                .hideAsParsed();
+
+        // android.test.base should be removed from the libraries because it is provided
+        // on the bootclasspath and providing both increases start up cost unnecessarily.
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.O)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void targeted_at_O_in_usesOptionalLibraries() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.O)
+                .addUsesOptionalLibrary(ANDROID_TEST_BASE)
+                .hideAsParsed();
+
+        // android.test.base should be removed from the libraries because it is provided
+        // on the bootclasspath and providing both increases start up cost unnecessarily.
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.O)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void in_usesLibraries() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .addUsesLibrary(ANDROID_TEST_BASE)
+                .hideAsParsed();
+
+        // android.test.base should be removed from the libraries because it is provided
+        // on the bootclasspath and providing both increases start up cost unnecessarily.
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void in_usesOptionalLibraries() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+                .addUsesOptionalLibrary(ANDROID_TEST_BASE)
+                .hideAsParsed();
+
+        // android.test.base should be removed from the libraries because it is provided
+        // on the bootclasspath and providing both increases start up cost unnecessarily.
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void in_bothLibraries() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+                .addUsesLibrary(ANDROID_TEST_BASE)
+                .addUsesOptionalLibrary(ANDROID_TEST_BASE)
+                .hideAsParsed();
+
+        // android.test.base should be removed from the libraries because it is provided
+        // on the bootclasspath and providing both increases start up cost unnecessarily.
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        checkBackwardsCompatibility(before, after);
+    }
+
+    private void checkBackwardsCompatibility(ParsedPackage before, AndroidPackage after) {
+        // TODO(b/72538146) - Cannot use constructor reference here because it is also used in
+        // PackageBackwardCompatibility and that seems to create a package-private lambda in
+        // android.content.pm which this then tries to reuse but fails because it cannot access
+        // package-private classes/members because the test is loaded by a different ClassLoader
+        // than the lambda.
+        checkBackwardsCompatibility(before, after,
+                () -> new RemoveUnnecessaryAndroidTestBaseLibrary());
+    }
+
+}
diff --git a/core/tests/coretests/src/android/content/pm/parsing/library/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java b/core/tests/coretests/src/android/content/pm/parsing/library/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java
new file mode 100644
index 0000000..d3494d9
--- /dev/null
+++ b/core/tests/coretests/src/android/content/pm/parsing/library/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm.parsing.library;
+
+import static android.content.pm.parsing.library.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY;
+
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.PackageImpl;
+import android.content.pm.parsing.ParsedPackage;
+import android.content.pm.parsing.library.PackageBackwardCompatibility.RemoveUnnecessaryOrgApacheHttpLegacyLibrary;
+import android.os.Build;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Test for {@link RemoveUnnecessaryOrgApacheHttpLegacyLibrary}
+ */
+@SmallTest
+@RunWith(JUnit4.class)
+public class RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest
+        extends PackageSharedLibraryUpdaterTest {
+
+    private static final String OTHER_LIBRARY = "other.library";
+
+    @Test
+    public void targeted_at_O() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.O)
+                .hideAsParsed();
+
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.O)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        // No change required.
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void targeted_at_O_not_empty_usesLibraries() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.O)
+                .addUsesLibrary(OTHER_LIBRARY)
+                .hideAsParsed();
+
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.O)
+                .addUsesLibrary(OTHER_LIBRARY)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        // No change required.
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void targeted_at_O_in_usesLibraries() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.O)
+                .addUsesLibrary(ORG_APACHE_HTTP_LEGACY)
+                .hideAsParsed();
+
+        // org.apache.http.legacy should be removed from the libraries because it is provided
+        // on the bootclasspath and providing both increases start up cost unnecessarily.
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.O)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void targeted_at_O_in_usesOptionalLibraries() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.O)
+                .addUsesOptionalLibrary(ORG_APACHE_HTTP_LEGACY)
+                .hideAsParsed();
+
+        // org.apache.http.legacy should be removed from the libraries because it is provided
+        // on the bootclasspath and providing both increases start up cost unnecessarily.
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.O)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void in_usesLibraries() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+                .addUsesLibrary(ORG_APACHE_HTTP_LEGACY)
+                .hideAsParsed();
+
+        // org.apache.http.legacy should be removed from the libraries because it is provided
+        // on the bootclasspath and providing both increases start up cost unnecessarily.
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void in_usesOptionalLibraries() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+                .addUsesOptionalLibrary(ORG_APACHE_HTTP_LEGACY)
+                .hideAsParsed();
+
+        // org.apache.http.legacy should be removed from the libraries because it is provided
+        // on the bootclasspath and providing both increases start up cost unnecessarily.
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void in_bothLibraries() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+                .addUsesLibrary(ORG_APACHE_HTTP_LEGACY)
+                .addUsesOptionalLibrary(ORG_APACHE_HTTP_LEGACY)
+                .hideAsParsed();
+
+        // org.apache.http.legacy should be removed from the libraries because it is provided
+        // on the bootclasspath and providing both increases start up cost unnecessarily.
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        checkBackwardsCompatibility(before, after);
+    }
+
+    private void checkBackwardsCompatibility(ParsedPackage before, AndroidPackage after) {
+        // TODO(b/72538146) - Cannot use constructor reference here because it is also used in
+        // PackageBackwardCompatibility and that seems to create a package-private lambda in
+        // android.content.pm which this then tries to reuse but fails because it cannot access
+        // package-private classes/members because the test is loaded by a different ClassLoader
+        // than the lambda.
+        checkBackwardsCompatibility(before, after,
+                () -> new RemoveUnnecessaryOrgApacheHttpLegacyLibrary());
+    }
+}
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index de6cca5..21f5f89 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -29,6 +29,8 @@
 import android.content.pm.PackageManager.ComponentInfoFlags;
 import android.content.pm.PackageManager.PackageInfoFlags;
 import android.content.pm.PackageManager.ResolveInfoFlags;
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.ComponentParseUtils;
 import android.os.Bundle;
 import android.os.PersistableBundle;
 import android.util.ArraySet;
@@ -326,7 +328,7 @@
      * @param installed the new installed state
      * @return true if the installed state changed as a result
      */
-    public abstract boolean setInstalled(PackageParser.Package pkg,
+    public abstract boolean setInstalled(AndroidPackage pkg,
             @UserIdInt int userId, boolean installed);
 
     /**
@@ -405,7 +407,7 @@
      * Returns whether or not the given package represents a legacy system application released
      * prior to runtime permissions.
      */
-    public abstract boolean isLegacySystemApp(PackageParser.Package pkg);
+    public abstract boolean isLegacySystemApp(AndroidPackage pkg);
 
     /**
      * Get all overlay packages for a user.
@@ -497,13 +499,17 @@
     /**
      * Returns a package object for the given package name.
      */
-    public abstract @Nullable PackageParser.Package getPackage(@NonNull String packageName);
+    public abstract @Nullable AndroidPackage getPackage(@NonNull String packageName);
+
+    // TODO(b/135203078): PackageSetting can't be referenced directly. Should move to a server side
+    //  internal PM which is aware of PS.
+    public abstract @Nullable Object getPackageSetting(String packageName);
 
     /**
      * Returns a package for the given UID. If the UID is part of a shared user ID, one
      * of the packages will be chosen to be returned.
      */
-    public abstract @Nullable PackageParser.Package getPackage(int uid);
+    public abstract @Nullable AndroidPackage getPackage(int uid);
 
     /**
      * Returns a list without a change observer.
@@ -534,17 +540,19 @@
      */
     public abstract void removePackageListObserver(@NonNull PackageListObserver observer);
 
+    // TODO(b/135203078): PackageSetting can't be referenced directly
     /**
      * Returns a package object for the disabled system package name.
      */
-    public abstract @Nullable PackageParser.Package getDisabledSystemPackage(
-            @NonNull String packageName);
+    public abstract @Nullable Object getDisabledSystemPackage(@NonNull String packageName);
 
     /**
      * Returns the package name for the disabled system package.
      *
      * This is equivalent to
-     * {@link #getDisabledSystemPackage(String)}.{@link PackageParser.Package#packageName}
+     * {@link #getDisabledSystemPackage(String)}
+     *     .{@link com.android.server.pm.PackageSetting#pkg}
+     *     .{@link AndroidPackage#getPackageName()}
      */
     public abstract @Nullable String getDisabledSystemPackageName(@NonNull String packageName);
 
@@ -579,7 +587,7 @@
      * @see #canAccessInstantApps
      */
     public abstract boolean filterAppAccess(
-            @NonNull PackageParser.Package pkg, int callingUid, int userId);
+            @NonNull AndroidPackage pkg, int callingUid, int userId);
 
     /**
      * Returns whether or not access to the application should be filtered.
@@ -653,7 +661,8 @@
             throws IOException;
 
     /** Returns {@code true} if the specified component is enabled and matches the given flags. */
-    public abstract boolean isEnabledAndMatches(@NonNull ComponentInfo info, int flags, int userId);
+    public abstract boolean isEnabledAndMatches(
+            @NonNull ComponentParseUtils.ParsedComponent component, int flags, int userId);
 
     /** Returns {@code true} if the given user requires extra badging for icons. */
     public abstract boolean userNeedsBadging(int userId);
@@ -664,14 +673,14 @@
      *
      * @param actionLocked action to be performed
      */
-    public abstract void forEachPackage(Consumer<PackageParser.Package> actionLocked);
+    public abstract void forEachPackage(Consumer<AndroidPackage> actionLocked);
 
     /**
      * Perform the given action for each installed package for a user.
      * Note that packages lock will be held while performin the actions.
      */
     public abstract void forEachInstalledPackage(
-            @NonNull Consumer<PackageParser.Package> actionLocked, @UserIdInt int userId);
+            @NonNull Consumer<AndroidPackage> actionLocked, @UserIdInt int userId);
 
     /** Returns the list of enabled components */
     public abstract ArraySet<String> getEnabledComponents(String packageName, int userId);
@@ -806,7 +815,7 @@
      * Otherwise, {@code false}.
      */
     public abstract boolean isCallerInstallerOfRecord(
-            @NonNull PackageParser.Package pkg, int callingUid);
+            @NonNull AndroidPackage pkg, int callingUid);
 
     /** Returns whether or not default runtime permissions are granted for the given user */
     public abstract boolean areDefaultRuntimePermissionsGranted(@UserIdInt int userId);
diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
index 14ef2d3a..be548a2 100644
--- a/services/core/java/com/android/server/pm/AppsFilter.java
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -26,8 +26,11 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
-import android.content.pm.PackageParser;
-import android.content.pm.ProviderInfo;
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.ComponentParseUtils;
+import android.content.pm.parsing.ComponentParseUtils.ParsedComponent;
+import android.content.pm.parsing.ComponentParseUtils.ParsedIntentInfo;
+import android.content.pm.parsing.ComponentParseUtils.ParsedProvider;
 import android.net.Uri;
 import android.os.Process;
 import android.os.Trace;
diff --git a/services/core/java/com/android/server/pm/ComponentResolver.java b/services/core/java/com/android/server/pm/ComponentResolver.java
index b1eb7e7..591f749 100644
--- a/services/core/java/com/android/server/pm/ComponentResolver.java
+++ b/services/core/java/com/android/server/pm/ComponentResolver.java
@@ -21,7 +21,6 @@
 
 import static com.android.server.pm.PackageManagerService.DEBUG_PACKAGE_SCANNING;
 import static com.android.server.pm.PackageManagerService.DEBUG_REMOVE;
-import static com.android.server.pm.PackageManagerService.fixProcessName;
 
 import android.annotation.Nullable;
 import android.content.ComponentName;
@@ -33,13 +32,18 @@
 import android.content.pm.InstantAppResolveInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
-import android.content.pm.PackageParser;
-import android.content.pm.PackageParser.ActivityIntentInfo;
-import android.content.pm.PackageParser.ServiceIntentInfo;
 import android.content.pm.PackageUserState;
 import android.content.pm.ProviderInfo;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.ComponentParseUtils.ParsedActivity;
+import android.content.pm.parsing.ComponentParseUtils.ParsedActivityIntentInfo;
+import android.content.pm.parsing.ComponentParseUtils.ParsedProvider;
+import android.content.pm.parsing.ComponentParseUtils.ParsedProviderIntentInfo;
+import android.content.pm.parsing.ComponentParseUtils.ParsedService;
+import android.content.pm.parsing.ComponentParseUtils.ParsedServiceIntentInfo;
+import android.content.pm.parsing.PackageInfoUtils;
 import android.os.UserHandle;
 import android.util.ArrayMap;
 import android.util.ArraySet;
@@ -55,11 +59,14 @@
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Comparator;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
+import java.util.function.Function;
 
 /** Resolves all Android component types [activities, services, providers and receivers]. */
 public class ComponentResolver {
@@ -160,7 +167,7 @@
 
     /** All available receivers, for your resolving pleasure. */
     @GuardedBy("mLock")
-    private final ActivityIntentResolver mReceivers = new ActivityIntentResolver();
+    private final ActivityIntentResolver mReceivers = new ReceiverIntentResolver();
 
     /** All available services, for your resolving pleasure. */
     @GuardedBy("mLock")
@@ -168,7 +175,7 @@
 
     /** Mapping from provider authority [first directory in content URI codePath) to provider. */
     @GuardedBy("mLock")
-    private final ArrayMap<String, PackageParser.Provider> mProvidersByAuthority = new ArrayMap<>();
+    private final ArrayMap<String, ParsedProvider> mProvidersByAuthority = new ArrayMap<>();
 
     /** Whether or not processing protected filters should be deferred. */
     private boolean mDeferProtectedFilters = true;
@@ -183,7 +190,7 @@
      * /system partition in order to know which component is the setup wizard. This can
      * only ever be non-empty if {@link #mDeferProtectedFilters} is {@code true}.
      */
-    private List<PackageParser.ActivityIntentInfo> mProtectedFilters;
+    private List<ParsedActivityIntentInfo> mProtectedFilters;
 
     ComponentResolver(UserManagerService userManager,
             PackageManagerInternal packageManagerInternal,
@@ -194,28 +201,28 @@
     }
 
     /** Returns the given activity */
-    PackageParser.Activity getActivity(ComponentName component) {
+    ParsedActivity getActivity(ComponentName component) {
         synchronized (mLock) {
             return mActivities.mActivities.get(component);
         }
     }
 
     /** Returns the given provider */
-    PackageParser.Provider getProvider(ComponentName component) {
+    ParsedProvider getProvider(ComponentName component) {
         synchronized (mLock) {
             return mProviders.mProviders.get(component);
         }
     }
 
     /** Returns the given receiver */
-    PackageParser.Activity getReceiver(ComponentName component) {
+    ParsedActivity getReceiver(ComponentName component) {
         synchronized (mLock) {
             return mReceivers.mActivities.get(component);
         }
     }
 
     /** Returns the given service */
-    PackageParser.Service getService(ComponentName component) {
+    ParsedService getService(ComponentName component) {
         synchronized (mLock) {
             return mServices.mServices.get(component);
         }
@@ -230,7 +237,7 @@
 
     @Nullable
     List<ResolveInfo> queryActivities(Intent intent, String resolvedType, int flags,
-            List<PackageParser.Activity> activities, int userId) {
+            List<ParsedActivity> activities, int userId) {
         synchronized (mLock) {
             return mActivities.queryIntentForPackage(
                     intent, resolvedType, flags, activities, userId);
@@ -246,7 +253,7 @@
 
     @Nullable
     List<ResolveInfo> queryProviders(Intent intent, String resolvedType, int flags,
-            List<PackageParser.Provider> providers, int userId) {
+            List<ParsedProvider> providers, int userId) {
         synchronized (mLock) {
             return mProviders.queryIntentForPackage(intent, resolvedType, flags, providers, userId);
         }
@@ -261,25 +268,34 @@
         List<ProviderInfo> providerList = null;
         synchronized (mLock) {
             for (int i = mProviders.mProviders.size() - 1; i >= 0; --i) {
-                final PackageParser.Provider p = mProviders.mProviders.valueAt(i);
-                final PackageSetting ps = (PackageSetting) p.owner.mExtras;
+                final ParsedProvider p = mProviders.mProviders.valueAt(i);
+                if (p.getAuthority() == null) {
+                    continue;
+                }
+
+                final PackageSetting ps =
+                        (PackageSetting) sPackageManagerInternal.getPackageSetting(
+                                p.getPackageName());
                 if (ps == null) {
                     continue;
                 }
-                if (p.info.authority == null) {
+
+                AndroidPackage pkg = sPackageManagerInternal.getPackage(p.getPackageName());
+                if (pkg == null) {
                     continue;
                 }
-                if (processName != null && (!p.info.processName.equals(processName)
-                        || !UserHandle.isSameApp(p.info.applicationInfo.uid, uid))) {
+
+                if (processName != null && (!p.getProcessName().equals(processName)
+                        || !UserHandle.isSameApp(pkg.getUid(), uid))) {
                     continue;
                 }
                 // See PM.queryContentProviders()'s javadoc for why we have the metaData parameter.
                 if (metaDataKey != null
-                        && (p.metaData == null || !p.metaData.containsKey(metaDataKey))) {
+                        && (p.getMetaData() == null || !p.getMetaData().containsKey(metaDataKey))) {
                     continue;
                 }
-                final ProviderInfo info = PackageParser.generateProviderInfo(
-                        p, flags, ps.readUserState(userId), userId);
+                final ProviderInfo info = PackageInfoUtils.generateProviderInfo(
+                        pkg, p, flags, ps.readUserState(userId), userId);
                 if (info == null) {
                     continue;
                 }
@@ -295,15 +311,21 @@
     @Nullable
     ProviderInfo queryProvider(String authority, int flags, int userId) {
         synchronized (mLock) {
-            final PackageParser.Provider p = mProvidersByAuthority.get(authority);
+            final ParsedProvider p = mProvidersByAuthority.get(authority);
             if (p == null) {
                 return null;
             }
-            final PackageSetting ps = (PackageSetting) p.owner.mExtras;
+            final PackageSetting ps = (PackageSetting) sPackageManagerInternal.getPackageSetting(
+                    p.getPackageName());
             if (ps == null) {
                 return null;
             }
-            return PackageParser.generateProviderInfo(p, flags, ps.readUserState(userId), userId);
+            final AndroidPackage pkg = sPackageManagerInternal.getPackage(p.getPackageName());
+            if (pkg == null) {
+                return null;
+            }
+            return PackageInfoUtils.generateProviderInfo(pkg, p, flags,
+                    ps.readUserState(userId), userId);
         }
     }
 
@@ -311,20 +333,29 @@
             int userId) {
         synchronized (mLock) {
             for (int i = mProvidersByAuthority.size() - 1; i >= 0; --i) {
-                final PackageParser.Provider p = mProvidersByAuthority.valueAt(i);
-                final PackageSetting ps = (PackageSetting) p.owner.mExtras;
+                final ParsedProvider p = mProvidersByAuthority.valueAt(i);
+                if (!p.isSyncable()) {
+                    continue;
+                }
+
+                final PackageSetting ps =
+                        (PackageSetting) sPackageManagerInternal.getPackageSetting(
+                                p.getPackageName());
                 if (ps == null) {
                     continue;
                 }
-                if (!p.syncable) {
+
+                final AndroidPackage pkg = sPackageManagerInternal.getPackage(p.getPackageName());
+                if (pkg == null) {
                     continue;
                 }
-                if (safeMode
-                        && (p.info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
+
+                if (safeMode && (pkg.getFlags() & ApplicationInfo.FLAG_SYSTEM) == 0) {
                     continue;
                 }
                 final ProviderInfo info =
-                        PackageParser.generateProviderInfo(p, 0, ps.readUserState(userId), userId);
+                        PackageInfoUtils.generateProviderInfo(pkg, p, 0,
+                                ps.readUserState(userId), userId);
                 if (info == null) {
                     continue;
                 }
@@ -343,7 +374,7 @@
 
     @Nullable
     List<ResolveInfo> queryReceivers(Intent intent, String resolvedType, int flags,
-            List<PackageParser.Activity> receivers, int userId) {
+            List<ParsedActivity> receivers, int userId) {
         synchronized (mLock) {
             return mReceivers.queryIntentForPackage(intent, resolvedType, flags, receivers, userId);
         }
@@ -358,7 +389,7 @@
 
     @Nullable
     List<ResolveInfo> queryServices(Intent intent, String resolvedType, int flags,
-            List<PackageParser.Service> services, int userId) {
+            List<ParsedService> services, int userId) {
         synchronized (mLock) {
             return mServices.queryIntentForPackage(intent, resolvedType, flags, services, userId);
         }
@@ -372,15 +403,15 @@
     }
 
     /** Asserts none of the providers defined in the given package haven't already been defined. */
-    void assertProvidersNotDefined(PackageParser.Package pkg) throws PackageManagerException {
+    void assertProvidersNotDefined(AndroidPackage pkg) throws PackageManagerException {
         synchronized (mLock) {
             assertProvidersNotDefinedLocked(pkg);
         }
     }
 
     /** Add all components defined in the given package to the internal structures. */
-    void addAllComponents(PackageParser.Package pkg, boolean chatty) {
-        final ArrayList<PackageParser.ActivityIntentInfo> newIntents = new ArrayList<>();
+    void addAllComponents(AndroidPackage pkg, boolean chatty) {
+        final ArrayList<ParsedActivityIntentInfo> newIntents = new ArrayList<>();
         synchronized (mLock) {
             addActivitiesLocked(pkg, newIntents, chatty);
             addReceiversLocked(pkg, chatty);
@@ -393,17 +424,19 @@
                         PACKAGE_SETUP_WIZARD, UserHandle.USER_SYSTEM));
 
         for (int i = newIntents.size() - 1; i >= 0; --i) {
-            final PackageParser.ActivityIntentInfo intentInfo = newIntents.get(i);
-            final PackageParser.Package disabledPkg = sPackageManagerInternal
-                    .getDisabledSystemPackage(intentInfo.activity.info.packageName);
-            final List<PackageParser.Activity> systemActivities =
-                    disabledPkg != null ? disabledPkg.activities : null;
+            final ParsedActivityIntentInfo intentInfo = newIntents.get(i);
+            final PackageSetting disabledPkgSetting = (PackageSetting) sPackageManagerInternal
+                    .getDisabledSystemPackage(intentInfo.getPackageName());
+            final AndroidPackage disabledPkg =
+                    disabledPkgSetting == null ? null : disabledPkgSetting.pkg;
+            final List<ParsedActivity> systemActivities =
+                    disabledPkg != null ? disabledPkg.getActivities() : null;
             adjustPriority(systemActivities, intentInfo, setupWizardPackage);
         }
     }
 
     /** Removes all components defined in the given package from the internal structures. */
-    void removeAllComponents(PackageParser.Package pkg, boolean chatty) {
+    void removeAllComponents(AndroidPackage pkg, boolean chatty) {
         synchronized (mLock) {
             removeAllComponentsLocked(pkg, chatty);
         }
@@ -422,7 +455,7 @@
         if (mProtectedFilters == null || mProtectedFilters.size() == 0) {
             return;
         }
-        final List<ActivityIntentInfo> protectedFilters = mProtectedFilters;
+        final List<ParsedActivityIntentInfo> protectedFilters = mProtectedFilters;
         mProtectedFilters = null;
 
         // expect single setupwizard package
@@ -435,13 +468,13 @@
                     + " All protected intents capped to priority 0");
         }
         for (int i = protectedFilters.size() - 1; i >= 0; --i) {
-            final ActivityIntentInfo filter = protectedFilters.get(i);
-            if (filter.activity.info.packageName.equals(setupWizardPackage)) {
+            final ParsedActivityIntentInfo filter = protectedFilters.get(i);
+            if (filter.getPackageName().equals(setupWizardPackage)) {
                 if (DEBUG_FILTERS) {
                     Slog.i(TAG, "Found setup wizard;"
                             + " allow priority " + filter.getPriority() + ";"
-                            + " package: " + filter.activity.info.packageName
-                            + " activity: " + filter.activity.className
+                            + " package: " + filter.getPackageName()
+                            + " activity: " + filter.getClassName()
                             + " priority: " + filter.getPriority());
                 }
                 // skip setup wizard; allow it to keep the high priority filter
@@ -449,8 +482,8 @@
             }
             if (DEBUG_FILTERS) {
                 Slog.i(TAG, "Protected action; cap priority to 0;"
-                        + " package: " + filter.activity.info.packageName
-                        + " activity: " + filter.activity.className
+                        + " package: " + filter.getPackageName()
+                        + " activity: " + filter.getClassName()
                         + " origPrio: " + filter.getPriority());
             }
             filter.setPriority(0);
@@ -491,8 +524,8 @@
 
     void dumpContentProviders(PrintWriter pw, DumpState dumpState, String packageName) {
         boolean printedSomething = false;
-        for (PackageParser.Provider p : mProviders.mProviders.values()) {
-            if (packageName != null && !packageName.equals(p.info.packageName)) {
+        for (ParsedProvider p : mProviders.mProviders.values()) {
+            if (packageName != null && !packageName.equals(p.getPackageName())) {
                 continue;
             }
             if (!printedSomething) {
@@ -502,14 +535,17 @@
                 pw.println("Registered ContentProviders:");
                 printedSomething = true;
             }
-            pw.print("  "); p.printComponentShortName(pw); pw.println(":");
-            pw.print("    "); pw.println(p.toString());
+            pw.print("  ");
+            ComponentName.printShortString(pw, p.getPackageName(), p.className);
+            pw.println(":");
+            pw.print("    ");
+            pw.println(p.toString());
         }
         printedSomething = false;
-        for (Map.Entry<String, PackageParser.Provider> entry :
+        for (Map.Entry<String, ParsedProvider> entry :
                 mProvidersByAuthority.entrySet()) {
-            PackageParser.Provider p = entry.getValue();
-            if (packageName != null && !packageName.equals(p.info.packageName)) {
+            ParsedProvider p = entry.getValue();
+            if (packageName != null && !packageName.equals(p.getPackageName())) {
                 continue;
             }
             if (!printedSomething) {
@@ -521,25 +557,43 @@
             }
             pw.print("  ["); pw.print(entry.getKey()); pw.println("]:");
             pw.print("    "); pw.println(p.toString());
-            if (p.info != null && p.info.applicationInfo != null) {
-                final String appInfo = p.info.applicationInfo.toString();
-                pw.print("      applicationInfo="); pw.println(appInfo);
+
+            AndroidPackage pkg = sPackageManagerInternal.getPackage(p.getPackageName());
+
+            if (pkg != null) {
+                // TODO(b/135203078): Print AppInfo?
+                pw.print("      applicationInfo="); pw.println(pkg.toAppInfo());
             }
         }
     }
 
-    void dumpServicePermissions(PrintWriter pw, DumpState dumpState, String packageName) {
+    void dumpServicePermissions(PrintWriter pw, DumpState dumpState) {
         if (dumpState.onTitlePrinted()) pw.println();
         pw.println("Service permissions:");
 
-        final Iterator<ServiceIntentInfo> filterIterator = mServices.filterIterator();
+        final Iterator<ParsedServiceIntentInfo> filterIterator = mServices.filterIterator();
         while (filterIterator.hasNext()) {
-            final ServiceIntentInfo info = filterIterator.next();
-            final ServiceInfo serviceInfo = info.service.info;
-            final String permission = serviceInfo.permission;
+            final ParsedServiceIntentInfo info = filterIterator.next();
+
+            ParsedService service = null;
+
+            AndroidPackage pkg = sPackageManagerInternal.getPackage(info.getPackageName());
+            if (pkg != null && pkg.getServices() != null) {
+                for (ParsedService parsedService : pkg.getServices()) {
+                    if (Objects.equals(parsedService.className, info.getClassName())) {
+                        service = parsedService;
+                    }
+                }
+            }
+
+            if (service == null) {
+                continue;
+            }
+
+            final String permission = service.getPermission();
             if (permission != null) {
                 pw.print("    ");
-                pw.print(serviceInfo.getComponentName().flattenToShortString());
+                pw.print(service.getComponentName().flattenToShortString());
                 pw.print(": ");
                 pw.println(permission);
             }
@@ -547,14 +601,12 @@
     }
 
     @GuardedBy("mLock")
-    private void addActivitiesLocked(PackageParser.Package pkg,
-            List<PackageParser.ActivityIntentInfo> newIntents, boolean chatty) {
-        final int activitiesSize = pkg.activities.size();
+    private void addActivitiesLocked(AndroidPackage pkg,
+            List<ParsedActivityIntentInfo> newIntents, boolean chatty) {
+        final int activitiesSize = ArrayUtils.size(pkg.getActivities());
         StringBuilder r = null;
         for (int i = 0; i < activitiesSize; i++) {
-            PackageParser.Activity a = pkg.activities.get(i);
-            a.info.processName =
-                    fixProcessName(pkg.applicationInfo.processName, a.info.processName);
+            ParsedActivity a = pkg.getActivities().get(i);
             mActivities.addActivity(a, "activity", newIntents);
             if (DEBUG_PACKAGE_SCANNING && chatty) {
                 if (r == null) {
@@ -562,7 +614,7 @@
                 } else {
                     r.append(' ');
                 }
-                r.append(a.info.name);
+                r.append(a.getName());
             }
         }
         if (DEBUG_PACKAGE_SCANNING && chatty) {
@@ -571,20 +623,17 @@
     }
 
     @GuardedBy("mLock")
-    private void addProvidersLocked(PackageParser.Package pkg, boolean chatty) {
-        final int providersSize = pkg.providers.size();
+    private void addProvidersLocked(AndroidPackage pkg, boolean chatty) {
+        final int providersSize = ArrayUtils.size(pkg.getProviders());
         StringBuilder r = null;
         for (int i = 0; i < providersSize; i++) {
-            PackageParser.Provider p = pkg.providers.get(i);
-            p.info.processName = fixProcessName(pkg.applicationInfo.processName,
-                    p.info.processName);
+            EffectiveProvider p = new EffectiveProvider(pkg.getProviders().get(i));
             mProviders.addProvider(p);
-            p.syncable = p.info.isSyncable;
-            if (p.info.authority != null) {
-                String[] names = p.info.authority.split(";");
-                p.info.authority = null;
+            if (p.getAuthority() != null) {
+                String[] names = p.getAuthority().split(";");
+                p.setEffectiveAuthority(null);
                 for (int j = 0; j < names.length; j++) {
-                    if (j == 1 && p.syncable) {
+                    if (j == 1 && p.isSyncable()) {
                         // We only want the first authority for a provider to possibly be
                         // syncable, so if we already added this provider using a different
                         // authority clear the syncable flag. We copy the provider before
@@ -592,23 +641,23 @@
                         // to a provider that we don't want to change.
                         // Only do this for the second authority since the resulting provider
                         // object can be the same for all future authorities for this provider.
-                        p = new PackageParser.Provider(p);
-                        p.syncable = false;
+                        p = new EffectiveProvider(p);
+                        p.setEffectiveSyncable(false);
                     }
                     if (!mProvidersByAuthority.containsKey(names[j])) {
                         mProvidersByAuthority.put(names[j], p);
-                        if (p.info.authority == null) {
-                            p.info.authority = names[j];
+                        if (p.getAuthority() == null) {
+                            p.setEffectiveAuthority(names[j]);
                         } else {
-                            p.info.authority = p.info.authority + ";" + names[j];
+                            p.setEffectiveAuthority(p.getAuthority() + ";" + names[j]);
                         }
                         if (DEBUG_PACKAGE_SCANNING && chatty) {
                             Log.d(TAG, "Registered content provider: " + names[j]
-                                    + ", className = " + p.info.name
-                                    + ", isSyncable = " + p.info.isSyncable);
+                                    + ", className = " + p.getName()
+                                    + ", isSyncable = " + p.isSyncable());
                         }
                     } else {
-                        final PackageParser.Provider other =
+                        final ParsedProvider other =
                                 mProvidersByAuthority.get(names[j]);
                         final ComponentName component =
                                 (other != null && other.getComponentName() != null)
@@ -616,7 +665,7 @@
                         final String packageName =
                                 component != null ? component.getPackageName() : "?";
                         Slog.w(TAG, "Skipping provider name " + names[j]
-                                + " (in package " + pkg.applicationInfo.packageName + ")"
+                                + " (in package " + pkg.getAppInfoPackageName() + ")"
                                 + ": name already used by " + packageName);
                     }
                 }
@@ -627,7 +676,7 @@
                 } else {
                     r.append(' ');
                 }
-                r.append(p.info.name);
+                r.append(p.getName());
             }
         }
         if (DEBUG_PACKAGE_SCANNING && chatty) {
@@ -636,13 +685,11 @@
     }
 
     @GuardedBy("mLock")
-    private void addReceiversLocked(PackageParser.Package pkg, boolean chatty) {
-        final int receiversSize = pkg.receivers.size();
+    private void addReceiversLocked(AndroidPackage pkg, boolean chatty) {
+        final int receiversSize = ArrayUtils.size(pkg.getReceivers());
         StringBuilder r = null;
         for (int i = 0; i < receiversSize; i++) {
-            PackageParser.Activity a = pkg.receivers.get(i);
-            a.info.processName = fixProcessName(pkg.applicationInfo.processName,
-                    a.info.processName);
+            ParsedActivity a = pkg.getReceivers().get(i);
             mReceivers.addActivity(a, "receiver", null);
             if (DEBUG_PACKAGE_SCANNING && chatty) {
                 if (r == null) {
@@ -650,7 +697,7 @@
                 } else {
                     r.append(' ');
                 }
-                r.append(a.info.name);
+                r.append(a.getName());
             }
         }
         if (DEBUG_PACKAGE_SCANNING && chatty) {
@@ -659,13 +706,11 @@
     }
 
     @GuardedBy("mLock")
-    private void addServicesLocked(PackageParser.Package pkg, boolean chatty) {
-        final int servicesSize = pkg.services.size();
+    private void addServicesLocked(AndroidPackage pkg, boolean chatty) {
+        final int servicesSize = ArrayUtils.size(pkg.getServices());
         StringBuilder r = null;
         for (int i = 0; i < servicesSize; i++) {
-            PackageParser.Service s = pkg.services.get(i);
-            s.info.processName = fixProcessName(pkg.applicationInfo.processName,
-                    s.info.processName);
+            ParsedService s = pkg.getServices().get(i);
             mServices.addService(s);
             if (DEBUG_PACKAGE_SCANNING && chatty) {
                 if (r == null) {
@@ -673,7 +718,7 @@
                 } else {
                     r.append(' ');
                 }
-                r.append(s.info.name);
+                r.append(s.getName());
             }
         }
         if (DEBUG_PACKAGE_SCANNING && chatty) {
@@ -681,13 +726,12 @@
         }
     }
 
-
     /**
      * <em>WARNING</em> for performance reasons, the passed in intentList WILL BE
      * MODIFIED. Do not pass in a list that should not be changed.
      */
-    private static <T> void getIntentListSubset(List<ActivityIntentInfo> intentList,
-            IterGenerator<T> generator, Iterator<T> searchIterator) {
+    private static <T> void getIntentListSubset(List<ParsedActivityIntentInfo> intentList,
+            Function<ParsedActivityIntentInfo, Iterator<T>> generator, Iterator<T> searchIterator) {
         // loop through the set of actions; every one must be found in the intent filter
         while (searchIterator.hasNext()) {
             // we must have at least one filter in the list to consider a match
@@ -698,14 +742,14 @@
             final T searchAction = searchIterator.next();
 
             // loop through the set of intent filters
-            final Iterator<ActivityIntentInfo> intentIter = intentList.iterator();
+            final Iterator<ParsedActivityIntentInfo> intentIter = intentList.iterator();
             while (intentIter.hasNext()) {
-                final ActivityIntentInfo intentInfo = intentIter.next();
+                final ParsedActivityIntentInfo intentInfo = intentIter.next();
                 boolean selectionFound = false;
 
                 // loop through the intent filter's selection criteria; at least one
                 // of them must match the searched criteria
-                final Iterator<T> intentSelectionIter = generator.generate(intentInfo);
+                final Iterator<T> intentSelectionIter = generator.apply(intentInfo);
                 while (intentSelectionIter != null && intentSelectionIter.hasNext()) {
                     final T intentSelection = intentSelectionIter.next();
                     if (intentSelection != null && intentSelection.equals(searchAction)) {
@@ -723,7 +767,7 @@
         }
     }
 
-    private static boolean isProtectedAction(ActivityIntentInfo filter) {
+    private static boolean isProtectedAction(ParsedActivityIntentInfo filter) {
         final Iterator<String> actionsIter = filter.actionsIterator();
         while (actionsIter != null && actionsIter.hasNext()) {
             final String filterAction = actionsIter.next();
@@ -737,20 +781,20 @@
     /**
      * Finds a privileged activity that matches the specified activity names.
      */
-    private static PackageParser.Activity findMatchingActivity(
-            List<PackageParser.Activity> activityList, ActivityInfo activityInfo) {
-        for (PackageParser.Activity sysActivity : activityList) {
-            if (sysActivity.info.name.equals(activityInfo.name)) {
+    private static ParsedActivity findMatchingActivity(
+            List<ParsedActivity> activityList, ParsedActivity activityInfo) {
+        for (ParsedActivity sysActivity : activityList) {
+            if (sysActivity.getName().equals(activityInfo.getName())) {
                 return sysActivity;
             }
-            if (sysActivity.info.name.equals(activityInfo.targetActivity)) {
+            if (sysActivity.getName().equals(activityInfo.targetActivity)) {
                 return sysActivity;
             }
-            if (sysActivity.info.targetActivity != null) {
-                if (sysActivity.info.targetActivity.equals(activityInfo.name)) {
+            if (sysActivity.targetActivity != null) {
+                if (sysActivity.targetActivity.equals(activityInfo.getName())) {
                     return sysActivity;
                 }
-                if (sysActivity.info.targetActivity.equals(activityInfo.targetActivity)) {
+                if (sysActivity.targetActivity.equals(activityInfo.targetActivity)) {
                     return sysActivity;
                 }
             }
@@ -771,24 +815,23 @@
      * <em>NOTE:</em> There is one exception. For security reasons, the setup wizard is
      * allowed to obtain any priority on any action.
      */
-    private void adjustPriority(List<PackageParser.Activity> systemActivities,
-            ActivityIntentInfo intent, String setupWizardPackage) {
+    private void adjustPriority(List<ParsedActivity> systemActivities,
+            ParsedActivityIntentInfo intent, String setupWizardPackage) {
         // nothing to do; priority is fine as-is
         if (intent.getPriority() <= 0) {
             return;
         }
 
-        final ActivityInfo activityInfo = intent.activity.info;
-        final ApplicationInfo applicationInfo = activityInfo.applicationInfo;
+        AndroidPackage pkg = sPackageManagerInternal.getPackage(intent.getPackageName());
 
         final boolean privilegedApp =
-                ((applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0);
+                ((pkg.getPrivateFlags() & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0);
         if (!privilegedApp) {
             // non-privileged applications can never define a priority >0
             if (DEBUG_FILTERS) {
                 Slog.i(TAG, "Non-privileged app; cap priority to 0;"
-                        + " package: " + applicationInfo.packageName
-                        + " activity: " + intent.activity.className
+                        + " package: " + pkg.getPackageName()
+                        + " activity: " + intent.getClassName()
                         + " origPrio: " + intent.getPriority());
             }
             intent.setPriority(0);
@@ -812,8 +855,8 @@
                     mProtectedFilters.add(intent);
                     if (DEBUG_FILTERS) {
                         Slog.i(TAG, "Protected action; save for later;"
-                                + " package: " + applicationInfo.packageName
-                                + " activity: " + intent.activity.className
+                                + " package: " + pkg.getPackageName()
+                                + " activity: " + intent.getClassName()
                                 + " origPrio: " + intent.getPriority());
                     }
                     return;
@@ -822,12 +865,12 @@
                         Slog.i(TAG, "No setup wizard;"
                                 + " All protected intents capped to priority 0");
                     }
-                    if (intent.activity.info.packageName.equals(setupWizardPackage)) {
+                    if (intent.getPackageName().equals(setupWizardPackage)) {
                         if (DEBUG_FILTERS) {
                             Slog.i(TAG, "Found setup wizard;"
                                     + " allow priority " + intent.getPriority() + ";"
-                                    + " package: " + intent.activity.info.packageName
-                                    + " activity: " + intent.activity.className
+                                    + " package: " + intent.getPackageName()
+                                    + " activity: " + intent.getClassName()
                                     + " priority: " + intent.getPriority());
                         }
                         // setup wizard gets whatever it wants
@@ -835,8 +878,8 @@
                     }
                     if (DEBUG_FILTERS) {
                         Slog.i(TAG, "Protected action; cap priority to 0;"
-                                + " package: " + intent.activity.info.packageName
-                                + " activity: " + intent.activity.className
+                                + " package: " + intent.getPackageName()
+                                + " activity: " + intent.getClassName()
                                 + " origPrio: " + intent.getPriority());
                     }
                     intent.setPriority(0);
@@ -848,14 +891,28 @@
         }
 
         // privileged app unbundled update ... try to find the same activity
-        final PackageParser.Activity foundActivity =
-                findMatchingActivity(systemActivities, activityInfo);
+
+        ParsedActivity foundActivity = null;
+        ParsedActivity activity = null;
+
+        if (pkg.getActivities() != null) {
+            for (ParsedActivity parsedProvider : pkg.getActivities()) {
+                if (Objects.equals(parsedProvider.className, intent.getClassName())) {
+                    activity = parsedProvider;
+                }
+            }
+        }
+
+        if (activity != null) {
+            foundActivity = findMatchingActivity(systemActivities, activity);
+        }
+
         if (foundActivity == null) {
             // this is a new activity; it cannot obtain >0 priority
             if (DEBUG_FILTERS) {
                 Slog.i(TAG, "New activity; cap priority to 0;"
-                        + " package: " + applicationInfo.packageName
-                        + " activity: " + intent.activity.className
+                        + " package: " + pkg.getPackageName()
+                        + " activity: " + intent.getClassName()
                         + " origPrio: " + intent.getPriority());
             }
             intent.setPriority(0);
@@ -865,19 +922,19 @@
         // found activity, now check for filter equivalence
 
         // a shallow copy is enough; we modify the list, not its contents
-        final List<ActivityIntentInfo> intentListCopy = new ArrayList<>(foundActivity.intents);
-        final List<ActivityIntentInfo> foundFilters = mActivities.findFilters(intent);
+        final List<ParsedActivityIntentInfo> intentListCopy =
+                new ArrayList<>(foundActivity.intents);
 
         // find matching action subsets
         final Iterator<String> actionsIterator = intent.actionsIterator();
         if (actionsIterator != null) {
-            getIntentListSubset(intentListCopy, new ActionIterGenerator(), actionsIterator);
+            getIntentListSubset(intentListCopy, IntentFilter::actionsIterator, actionsIterator);
             if (intentListCopy.size() == 0) {
                 // no more intents to match; we're not equivalent
                 if (DEBUG_FILTERS) {
                     Slog.i(TAG, "Mismatched action; cap priority to 0;"
-                            + " package: " + applicationInfo.packageName
-                            + " activity: " + intent.activity.className
+                            + " package: " + pkg.getPackageName()
+                            + " activity: " + intent.getClassName()
                             + " origPrio: " + intent.getPriority());
                 }
                 intent.setPriority(0);
@@ -888,13 +945,14 @@
         // find matching category subsets
         final Iterator<String> categoriesIterator = intent.categoriesIterator();
         if (categoriesIterator != null) {
-            getIntentListSubset(intentListCopy, new CategoriesIterGenerator(), categoriesIterator);
+            getIntentListSubset(intentListCopy, IntentFilter::categoriesIterator,
+                    categoriesIterator);
             if (intentListCopy.size() == 0) {
                 // no more intents to match; we're not equivalent
                 if (DEBUG_FILTERS) {
                     Slog.i(TAG, "Mismatched category; cap priority to 0;"
-                            + " package: " + applicationInfo.packageName
-                            + " activity: " + intent.activity.className
+                            + " package: " + pkg.getPackageName()
+                            + " activity: " + intent.getClassName()
                             + " origPrio: " + intent.getPriority());
                 }
                 intent.setPriority(0);
@@ -905,13 +963,13 @@
         // find matching schemes subsets
         final Iterator<String> schemesIterator = intent.schemesIterator();
         if (schemesIterator != null) {
-            getIntentListSubset(intentListCopy, new SchemesIterGenerator(), schemesIterator);
+            getIntentListSubset(intentListCopy, IntentFilter::schemesIterator, schemesIterator);
             if (intentListCopy.size() == 0) {
                 // no more intents to match; we're not equivalent
                 if (DEBUG_FILTERS) {
                     Slog.i(TAG, "Mismatched scheme; cap priority to 0;"
-                            + " package: " + applicationInfo.packageName
-                            + " activity: " + intent.activity.className
+                            + " package: " + pkg.getPackageName()
+                            + " activity: " + intent.getClassName()
                             + " origPrio: " + intent.getPriority());
                 }
                 intent.setPriority(0);
@@ -923,14 +981,14 @@
         final Iterator<IntentFilter.AuthorityEntry> authoritiesIterator =
                 intent.authoritiesIterator();
         if (authoritiesIterator != null) {
-            getIntentListSubset(intentListCopy, new AuthoritiesIterGenerator(),
+            getIntentListSubset(intentListCopy, IntentFilter::authoritiesIterator,
                     authoritiesIterator);
             if (intentListCopy.size() == 0) {
                 // no more intents to match; we're not equivalent
                 if (DEBUG_FILTERS) {
                     Slog.i(TAG, "Mismatched authority; cap priority to 0;"
-                            + " package: " + applicationInfo.packageName
-                            + " activity: " + intent.activity.className
+                            + " package: " + pkg.getPackageName()
+                            + " activity: " + intent.getClassName()
                             + " origPrio: " + intent.getPriority());
                 }
                 intent.setPriority(0);
@@ -947,8 +1005,8 @@
             if (DEBUG_FILTERS) {
                 Slog.i(TAG, "Found matching filter(s);"
                         + " cap priority to " + cappedPriority + ";"
-                        + " package: " + applicationInfo.packageName
-                        + " activity: " + intent.activity.className
+                        + " package: " + pkg.getPackageName()
+                        + " activity: " + intent.getClassName()
                         + " origPrio: " + intent.getPriority());
             }
             intent.setPriority(cappedPriority);
@@ -958,15 +1016,15 @@
     }
 
     @GuardedBy("mLock")
-    private void removeAllComponentsLocked(PackageParser.Package pkg, boolean chatty) {
+    private void removeAllComponentsLocked(AndroidPackage pkg, boolean chatty) {
         int componentSize;
         StringBuilder r;
         int i;
 
-        componentSize = pkg.activities.size();
+        componentSize = ArrayUtils.size(pkg.getActivities());
         r = null;
         for (i = 0; i < componentSize; i++) {
-            PackageParser.Activity a = pkg.activities.get(i);
+            ParsedActivity a = pkg.getActivities().get(i);
             mActivities.removeActivity(a, "activity");
             if (DEBUG_REMOVE && chatty) {
                 if (r == null) {
@@ -974,32 +1032,32 @@
                 } else {
                     r.append(' ');
                 }
-                r.append(a.info.name);
+                r.append(a.getName());
             }
         }
         if (DEBUG_REMOVE && chatty) {
             Log.d(TAG, "  Activities: " + (r == null ? "<NONE>" : r));
         }
 
-        componentSize = pkg.providers.size();
+        componentSize = ArrayUtils.size(pkg.getProviders());
         r = null;
         for (i = 0; i < componentSize; i++) {
-            PackageParser.Provider p = pkg.providers.get(i);
+            ParsedProvider p = pkg.getProviders().get(i);
             mProviders.removeProvider(p);
-            if (p.info.authority == null) {
+            if (p.getAuthority() == null) {
                 // Another content provider with this authority existed when this app was
                 // installed, so this authority is null. Ignore it as we don't have to
                 // unregister the provider.
                 continue;
             }
-            String[] names = p.info.authority.split(";");
+            String[] names = p.getAuthority().split(";");
             for (int j = 0; j < names.length; j++) {
                 if (mProvidersByAuthority.get(names[j]) == p) {
                     mProvidersByAuthority.remove(names[j]);
                     if (DEBUG_REMOVE && chatty) {
                         Log.d(TAG, "Unregistered content provider: " + names[j]
-                                + ", className = " + p.info.name + ", isSyncable = "
-                                + p.info.isSyncable);
+                                + ", className = " + p.getName() + ", isSyncable = "
+                                + p.isSyncable());
                     }
                 }
             }
@@ -1009,17 +1067,17 @@
                 } else {
                     r.append(' ');
                 }
-                r.append(p.info.name);
+                r.append(p.getName());
             }
         }
         if (DEBUG_REMOVE && chatty) {
             Log.d(TAG, "  Providers: " + (r == null ? "<NONE>" : r));
         }
 
-        componentSize = pkg.receivers.size();
+        componentSize = ArrayUtils.size(pkg.getReceivers());
         r = null;
         for (i = 0; i < componentSize; i++) {
-            PackageParser.Activity a = pkg.receivers.get(i);
+            ParsedActivity a = pkg.getReceivers().get(i);
             mReceivers.removeActivity(a, "receiver");
             if (DEBUG_REMOVE && chatty) {
                 if (r == null) {
@@ -1027,17 +1085,17 @@
                 } else {
                     r.append(' ');
                 }
-                r.append(a.info.name);
+                r.append(a.getName());
             }
         }
         if (DEBUG_REMOVE && chatty) {
             Log.d(TAG, "  Receivers: " + (r == null ? "<NONE>" : r));
         }
 
-        componentSize = pkg.services.size();
+        componentSize = ArrayUtils.size(pkg.getServices());
         r = null;
         for (i = 0; i < componentSize; i++) {
-            PackageParser.Service s = pkg.services.get(i);
+            ParsedService s = pkg.getServices().get(i);
             mServices.removeService(s);
             if (DEBUG_REMOVE && chatty) {
                 if (r == null) {
@@ -1045,7 +1103,7 @@
                 } else {
                     r.append(' ');
                 }
-                r.append(s.info.name);
+                r.append(s.getName());
             }
         }
         if (DEBUG_REMOVE && chatty) {
@@ -1054,26 +1112,26 @@
     }
 
     @GuardedBy("mLock")
-    private void assertProvidersNotDefinedLocked(PackageParser.Package pkg)
+    private void assertProvidersNotDefinedLocked(AndroidPackage pkg)
             throws PackageManagerException {
-        final int providersSize = pkg.providers.size();
+        final int providersSize = ArrayUtils.size(pkg.getProviders());
         int i;
         for (i = 0; i < providersSize; i++) {
-            PackageParser.Provider p = pkg.providers.get(i);
-            if (p.info.authority != null) {
-                final String[] names = p.info.authority.split(";");
+            ParsedProvider p = pkg.getProviders().get(i);
+            if (p.getAuthority() != null) {
+                final String[] names = p.getAuthority().split(";");
                 for (int j = 0; j < names.length; j++) {
                     if (mProvidersByAuthority.containsKey(names[j])) {
-                        final PackageParser.Provider other = mProvidersByAuthority.get(names[j]);
+                        final ParsedProvider other = mProvidersByAuthority.get(names[j]);
                         final String otherPackageName =
                                 (other != null && other.getComponentName() != null)
                                         ? other.getComponentName().getPackageName() : "?";
                         // if we're installing over the same already-installed package, this is ok
-                        if (!otherPackageName.equals(pkg.packageName)) {
+                        if (!otherPackageName.equals(pkg.getPackageName())) {
                             throw new PackageManagerException(
                                     INSTALL_FAILED_CONFLICTING_PROVIDER,
                                     "Can't install because provider name " + names[j]
-                                            + " (in package " + pkg.applicationInfo.packageName
+                                            + " (in package " + pkg.getPackageName()
                                             + ") is already used by " + otherPackageName);
                         }
                     }
@@ -1082,8 +1140,9 @@
         }
     }
 
-    private static final class ActivityIntentResolver
-            extends IntentResolver<PackageParser.ActivityIntentInfo, ResolveInfo> {
+    private static class ActivityIntentResolver
+            extends IntentResolver<ParsedActivityIntentInfo, ResolveInfo> {
+
         @Override
         public List<ResolveInfo> queryIntent(Intent intent, String resolvedType,
                 boolean defaultOnly, int userId) {
@@ -1104,24 +1163,24 @@
         }
 
         List<ResolveInfo> queryIntentForPackage(Intent intent, String resolvedType,
-                int flags, List<PackageParser.Activity> packageActivities, int userId) {
+                int flags, List<ParsedActivity> packageActivities, int userId) {
             if (!sUserManager.exists(userId)) {
                 return null;
             }
             if (packageActivities == null) {
-                return null;
+                return Collections.emptyList();
             }
             mFlags = flags;
             final boolean defaultOnly = (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0;
             final int activitiesSize = packageActivities.size();
-            ArrayList<PackageParser.ActivityIntentInfo[]> listCut = new ArrayList<>(activitiesSize);
+            ArrayList<ParsedActivityIntentInfo[]> listCut = new ArrayList<>(activitiesSize);
 
-            ArrayList<PackageParser.ActivityIntentInfo> intentFilters;
+            List<ParsedActivityIntentInfo> intentFilters;
             for (int i = 0; i < activitiesSize; ++i) {
                 intentFilters = packageActivities.get(i).intents;
                 if (intentFilters != null && intentFilters.size() > 0) {
-                    PackageParser.ActivityIntentInfo[] array =
-                            new PackageParser.ActivityIntentInfo[intentFilters.size()];
+                    ParsedActivityIntentInfo[] array =
+                            new ParsedActivityIntentInfo[intentFilters.size()];
                     intentFilters.toArray(array);
                     listCut.add(array);
                 }
@@ -1129,21 +1188,21 @@
             return super.queryIntentFromList(intent, resolvedType, defaultOnly, listCut, userId);
         }
 
-        private void addActivity(PackageParser.Activity a, String type,
-                List<PackageParser.ActivityIntentInfo> newIntents) {
+        private void addActivity(ParsedActivity a, String type,
+                List<ParsedActivityIntentInfo> newIntents) {
             mActivities.put(a.getComponentName(), a);
             if (DEBUG_SHOW_INFO) {
-                final CharSequence label = a.info.nonLocalizedLabel != null
-                        ? a.info.nonLocalizedLabel
-                        : a.info.name;
+                final CharSequence label = a.nonLocalizedLabel != null
+                        ? a.nonLocalizedLabel
+                        : a.getName();
                 Log.v(TAG, "  " + type + " " + label + ":");
             }
             if (DEBUG_SHOW_INFO) {
-                Log.v(TAG, "    Class=" + a.info.name);
+                Log.v(TAG, "    Class=" + a.getName());
             }
             final int intentsSize = a.intents.size();
             for (int j = 0; j < intentsSize; j++) {
-                PackageParser.ActivityIntentInfo intent = a.intents.get(j);
+                ParsedActivityIntentInfo intent = a.intents.get(j);
                 if (newIntents != null && "activity".equals(type)) {
                     newIntents.add(intent);
                 }
@@ -1152,23 +1211,23 @@
                     intent.dump(new LogPrinter(Log.VERBOSE, TAG), "      ");
                 }
                 if (!intent.debugCheck()) {
-                    Log.w(TAG, "==> For Activity " + a.info.name);
+                    Log.w(TAG, "==> For Activity " + a.getName());
                 }
                 addFilter(intent);
             }
         }
 
-        private void removeActivity(PackageParser.Activity a, String type) {
+        private void removeActivity(ParsedActivity a, String type) {
             mActivities.remove(a.getComponentName());
             if (DEBUG_SHOW_INFO) {
                 Log.v(TAG, "  " + type + " "
-                        + (a.info.nonLocalizedLabel != null ? a.info.nonLocalizedLabel
-                                : a.info.name) + ":");
-                Log.v(TAG, "    Class=" + a.info.name);
+                        + (a.nonLocalizedLabel != null ? a.nonLocalizedLabel
+                                : a.getName()) + ":");
+                Log.v(TAG, "    Class=" + a.getName());
             }
             final int intentsSize = a.intents.size();
             for (int j = 0; j < intentsSize; j++) {
-                PackageParser.ActivityIntentInfo intent = a.intents.get(j);
+                ParsedActivityIntentInfo intent = a.intents.get(j);
                 if (DEBUG_SHOW_INFO) {
                     Log.v(TAG, "    IntentFilter:");
                     intent.dump(new LogPrinter(Log.VERBOSE, TAG), "      ");
@@ -1179,11 +1238,11 @@
 
         @Override
         protected boolean allowFilterResult(
-                PackageParser.ActivityIntentInfo filter, List<ResolveInfo> dest) {
-            ActivityInfo filterAi = filter.activity.info;
+                ParsedActivityIntentInfo filter, List<ResolveInfo> dest) {
             for (int i = dest.size() - 1; i >= 0; --i) {
                 ActivityInfo destAi = dest.get(i).activityInfo;
-                if (destAi.name == filterAi.name && destAi.packageName == filterAi.packageName) {
+                if (Objects.equals(destAi.name, filter.getClassName())
+                        && Objects.equals(destAi.packageName, filter.getPackageName())) {
                     return false;
                 }
             }
@@ -1191,34 +1250,39 @@
         }
 
         @Override
-        protected ActivityIntentInfo[] newArray(int size) {
-            return new ActivityIntentInfo[size];
+        protected ParsedActivityIntentInfo[] newArray(int size) {
+            return new ParsedActivityIntentInfo[size];
         }
 
         @Override
-        protected boolean isFilterStopped(PackageParser.ActivityIntentInfo filter, int userId) {
+        protected boolean isFilterStopped(ParsedActivityIntentInfo filter, int userId) {
             if (!sUserManager.exists(userId)) return true;
-            PackageParser.Package p = filter.activity.owner;
-            if (p != null) {
-                PackageSetting ps = (PackageSetting) p.mExtras;
-                if (ps != null) {
-                    // System apps are never considered stopped for purposes of
-                    // filtering, because there may be no way for the user to
-                    // actually re-launch them.
-                    return (ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0
-                            && ps.getStopped(userId);
-                }
+
+            AndroidPackage pkg = sPackageManagerInternal.getPackage(filter.getPackageName());
+            if (pkg == null) {
+                return false;
             }
-            return false;
+
+            PackageSetting ps = (PackageSetting) sPackageManagerInternal.getPackageSetting(
+                    filter.getPackageName());
+            if (ps == null) {
+                return false;
+            }
+
+            // System apps are never considered stopped for purposes of
+            // filtering, because there may be no way for the user to
+            // actually re-launch them.
+            return (ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0
+                    && ps.getStopped(userId);
         }
 
         @Override
         protected boolean isPackageForFilter(String packageName,
-                PackageParser.ActivityIntentInfo info) {
-            return packageName.equals(info.activity.owner.packageName);
+                ParsedActivityIntentInfo info) {
+            return packageName.equals(info.getPackageName());
         }
 
-        private void log(String reason, ActivityIntentInfo info, int match,
+        private void log(String reason, ParsedActivityIntentInfo info, int match,
                 int userId) {
             Slog.w(TAG, reason
                     + "; match: "
@@ -1228,7 +1292,7 @@
         }
 
         @Override
-        protected ResolveInfo newResult(PackageParser.ActivityIntentInfo info,
+        protected ResolveInfo newResult(ParsedActivityIntentInfo info,
                 int match, int userId) {
             if (!sUserManager.exists(userId)) {
                 if (DEBUG) {
@@ -1236,7 +1300,29 @@
                 }
                 return null;
             }
-            if (!sPackageManagerInternal.isEnabledAndMatches(info.activity.info, mFlags, userId)) {
+
+            ParsedActivity activity = null;
+
+            AndroidPackage pkg = sPackageManagerInternal.getPackage(info.getPackageName());
+            if (pkg == null) {
+                return null;
+            }
+
+            // TODO(b/135203078): Consider more efficient ways of doing this.
+            List<ParsedActivity> activities = getResolveList(pkg);
+            if (activities != null) {
+                for (ParsedActivity parsedActivity : activities) {
+                    if (Objects.equals(parsedActivity.className, info.getClassName())) {
+                        activity = parsedActivity;
+                    }
+                }
+            }
+
+            if (activity == null) {
+                return null;
+            }
+
+            if (!sPackageManagerInternal.isEnabledAndMatches(activity, mFlags, userId)) {
                 if (DEBUG) {
                     log("!PackageManagerInternal.isEnabledAndMatches; mFlags="
                             + DebugUtils.flagsToString(PackageManager.class, "MATCH_", mFlags),
@@ -1244,8 +1330,8 @@
                 }
                 return null;
             }
-            final PackageParser.Activity activity = info.activity;
-            PackageSetting ps = (PackageSetting) activity.owner.mExtras;
+            PackageSetting ps = (PackageSetting) sPackageManagerInternal.getPackageSetting(
+                    info.getPackageName());
             if (ps == null) {
                 if (DEBUG) {
                     log("info.activity.owner.mExtras == null", info, match, userId);
@@ -1254,10 +1340,10 @@
             }
             final PackageUserState userState = ps.readUserState(userId);
             ActivityInfo ai =
-                    PackageParser.generateActivityInfo(activity, mFlags, userState, userId);
+                    PackageInfoUtils.generateActivityInfo(pkg, activity, mFlags, userState, userId);
             if (ai == null) {
                 if (DEBUG) {
-                    log("Failed to create ActivityInfo based on " + info.activity, info, match,
+                    log("Failed to create ActivityInfo based on " + activity, info, match,
                             userId);
                 }
                 return null;
@@ -1307,7 +1393,7 @@
             }
             res.handleAllWebDataURI = info.handleAllWebDataURI();
             res.priority = info.getPriority();
-            res.preferredOrder = activity.owner.mPreferredOrder;
+            res.preferredOrder = pkg.getPreferredOrder();
             //System.out.println("Result: " + res.activityInfo.className +
             //                   " = " + res.priority);
             res.match = match;
@@ -1332,40 +1418,64 @@
 
         @Override
         protected void dumpFilter(PrintWriter out, String prefix,
-                PackageParser.ActivityIntentInfo filter) {
+                ParsedActivityIntentInfo filter) {
+            ParsedActivity activity = null;
+
+            AndroidPackage pkg = sPackageManagerInternal.getPackage(filter.getPackageName());
+            if (pkg != null && pkg.getActivities() != null) {
+                for (ParsedActivity parsedActivity : pkg.getActivities()) {
+                    if (Objects.equals(parsedActivity.className, filter.getClassName())) {
+                        activity = parsedActivity;
+                    }
+                }
+            }
+
             out.print(prefix);
-            out.print(Integer.toHexString(System.identityHashCode(filter.activity)));
+            out.print(Integer.toHexString(System.identityHashCode(activity)));
             out.print(' ');
-            filter.activity.printComponentShortName(out);
+            ComponentName.printShortString(out, filter.getPackageName(), filter.getClassName());
             out.print(" filter ");
             out.println(Integer.toHexString(System.identityHashCode(filter)));
         }
 
         @Override
-        protected Object filterToLabel(PackageParser.ActivityIntentInfo filter) {
-            return filter.activity;
+        protected Object filterToLabel(ParsedActivityIntentInfo filter) {
+            return filter;
         }
 
         protected void dumpFilterLabel(PrintWriter out, String prefix, Object label, int count) {
-            PackageParser.Activity activity = (PackageParser.Activity) label;
+            ParsedActivityIntentInfo activity = (ParsedActivityIntentInfo) label;
             out.print(prefix);
             out.print(Integer.toHexString(System.identityHashCode(activity)));
             out.print(' ');
-            activity.printComponentShortName(out);
+            ComponentName.printShortString(out, activity.getPackageName(), activity.getClassName());
             if (count > 1) {
                 out.print(" ("); out.print(count); out.print(" filters)");
             }
             out.println();
         }
 
+        protected List<ParsedActivity> getResolveList(AndroidPackage pkg) {
+            return pkg.getActivities();
+        }
+
         // Keys are String (activity class name), values are Activity.
-        private final ArrayMap<ComponentName, PackageParser.Activity> mActivities =
+        private final ArrayMap<ComponentName, ParsedActivity> mActivities =
                 new ArrayMap<>();
         private int mFlags;
     }
 
+    // Both receivers and activities share a class, but point to different get methods
+    private static final class ReceiverIntentResolver extends ActivityIntentResolver {
+
+        @Override
+        protected List<ParsedActivity> getResolveList(AndroidPackage pkg) {
+            return pkg.getReceivers();
+        }
+    }
+
     private static final class ProviderIntentResolver
-            extends IntentResolver<PackageParser.ProviderIntentInfo, ResolveInfo> {
+            extends IntentResolver<ParsedProviderIntentInfo, ResolveInfo> {
         @Override
         public List<ResolveInfo> queryIntent(Intent intent, String resolvedType,
                 boolean defaultOnly, int userId) {
@@ -1387,24 +1497,24 @@
 
         @Nullable
         List<ResolveInfo> queryIntentForPackage(Intent intent, String resolvedType,
-                int flags, List<PackageParser.Provider> packageProviders, int userId) {
+                int flags, List<ParsedProvider> packageProviders, int userId) {
             if (!sUserManager.exists(userId)) {
                 return null;
             }
             if (packageProviders == null) {
-                return null;
+                return Collections.emptyList();
             }
             mFlags = flags;
             final boolean defaultOnly = (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0;
             final int providersSize = packageProviders.size();
-            ArrayList<PackageParser.ProviderIntentInfo[]> listCut = new ArrayList<>(providersSize);
+            ArrayList<ParsedProviderIntentInfo[]> listCut = new ArrayList<>(providersSize);
 
-            ArrayList<PackageParser.ProviderIntentInfo> intentFilters;
+            List<ParsedProviderIntentInfo> intentFilters;
             for (int i = 0; i < providersSize; ++i) {
-                intentFilters = packageProviders.get(i).intents;
+                intentFilters = packageProviders.get(i).getIntents();
                 if (intentFilters != null && intentFilters.size() > 0) {
-                    PackageParser.ProviderIntentInfo[] array =
-                            new PackageParser.ProviderIntentInfo[intentFilters.size()];
+                    ParsedProviderIntentInfo[] array =
+                            new ParsedProviderIntentInfo[intentFilters.size()];
                     intentFilters.toArray(array);
                     listCut.add(array);
                 }
@@ -1412,7 +1522,7 @@
             return super.queryIntentFromList(intent, resolvedType, defaultOnly, listCut, userId);
         }
 
-        void addProvider(PackageParser.Provider p) {
+        void addProvider(ParsedProvider p) {
             if (mProviders.containsKey(p.getComponentName())) {
                 Slog.w(TAG, "Provider " + p.getComponentName() + " already defined; ignoring");
                 return;
@@ -1421,39 +1531,39 @@
             mProviders.put(p.getComponentName(), p);
             if (DEBUG_SHOW_INFO) {
                 Log.v(TAG, "  "
-                        + (p.info.nonLocalizedLabel != null
-                                ? p.info.nonLocalizedLabel
-                                : p.info.name)
+                        + (p.nonLocalizedLabel != null
+                                ? p.nonLocalizedLabel
+                                : p.getName())
                         + ":");
-                Log.v(TAG, "    Class=" + p.info.name);
+                Log.v(TAG, "    Class=" + p.getName());
             }
-            final int intentsSize = p.intents.size();
+            final int intentsSize = p.getIntents().size();
             int j;
             for (j = 0; j < intentsSize; j++) {
-                PackageParser.ProviderIntentInfo intent = p.intents.get(j);
+                ParsedProviderIntentInfo intent = p.getIntents().get(j);
                 if (DEBUG_SHOW_INFO) {
                     Log.v(TAG, "    IntentFilter:");
                     intent.dump(new LogPrinter(Log.VERBOSE, TAG), "      ");
                 }
                 if (!intent.debugCheck()) {
-                    Log.w(TAG, "==> For Provider " + p.info.name);
+                    Log.w(TAG, "==> For Provider " + p.getName());
                 }
                 addFilter(intent);
             }
         }
 
-        void removeProvider(PackageParser.Provider p) {
+        void removeProvider(ParsedProvider p) {
             mProviders.remove(p.getComponentName());
             if (DEBUG_SHOW_INFO) {
-                Log.v(TAG, "  " + (p.info.nonLocalizedLabel != null
-                        ? p.info.nonLocalizedLabel
-                        : p.info.name) + ":");
-                Log.v(TAG, "    Class=" + p.info.name);
+                Log.v(TAG, "  " + (p.nonLocalizedLabel != null
+                        ? p.nonLocalizedLabel
+                        : p.getName()) + ":");
+                Log.v(TAG, "    Class=" + p.getName());
             }
-            final int intentsSize = p.intents.size();
+            final int intentsSize = p.getIntents().size();
             int j;
             for (j = 0; j < intentsSize; j++) {
-                PackageParser.ProviderIntentInfo intent = p.intents.get(j);
+                ParsedProviderIntentInfo intent = p.getIntents().get(j);
                 if (DEBUG_SHOW_INFO) {
                     Log.v(TAG, "    IntentFilter:");
                     intent.dump(new LogPrinter(Log.VERBOSE, TAG), "      ");
@@ -1464,12 +1574,11 @@
 
         @Override
         protected boolean allowFilterResult(
-                PackageParser.ProviderIntentInfo filter, List<ResolveInfo> dest) {
-            ProviderInfo filterPi = filter.provider.info;
+                ParsedProviderIntentInfo filter, List<ResolveInfo> dest) {
             for (int i = dest.size() - 1; i >= 0; i--) {
                 ProviderInfo destPi = dest.get(i).providerInfo;
-                if (destPi.name == filterPi.name
-                        && destPi.packageName == filterPi.packageName) {
+                if (Objects.equals(destPi.name, filter.getClassName())
+                        && Objects.equals(destPi.packageName, filter.getPackageName())) {
                     return false;
                 }
             }
@@ -1477,47 +1586,68 @@
         }
 
         @Override
-        protected PackageParser.ProviderIntentInfo[] newArray(int size) {
-            return new PackageParser.ProviderIntentInfo[size];
+        protected ParsedProviderIntentInfo[] newArray(int size) {
+            return new ParsedProviderIntentInfo[size];
         }
 
         @Override
-        protected boolean isFilterStopped(PackageParser.ProviderIntentInfo filter, int userId) {
+        protected boolean isFilterStopped(ParsedProviderIntentInfo filter, int userId) {
             if (!sUserManager.exists(userId)) {
                 return true;
             }
-            PackageParser.Package p = filter.provider.owner;
-            if (p != null) {
-                PackageSetting ps = (PackageSetting) p.mExtras;
-                if (ps != null) {
-                    // System apps are never considered stopped for purposes of
-                    // filtering, because there may be no way for the user to
-                    // actually re-launch them.
-                    return (ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0
-                            && ps.getStopped(userId);
-                }
+
+            AndroidPackage pkg = sPackageManagerInternal.getPackage(filter.getPackageName());
+            if (pkg == null) {
+                return false;
             }
-            return false;
+
+            PackageSetting ps = (PackageSetting) sPackageManagerInternal.getPackageSetting(
+                    filter.getPackageName());
+            if (ps == null) {
+                return false;
+            }
+
+            // System apps are never considered stopped for purposes of
+            // filtering, because there may be no way for the user to
+            // actually re-launch them.
+            return (ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0
+                    && ps.getStopped(userId);
         }
 
         @Override
         protected boolean isPackageForFilter(String packageName,
-                PackageParser.ProviderIntentInfo info) {
-            return packageName.equals(info.provider.owner.packageName);
+                ParsedProviderIntentInfo info) {
+            return packageName.equals(info.getPackageName());
         }
 
         @Override
-        protected ResolveInfo newResult(PackageParser.ProviderIntentInfo filter,
+        protected ResolveInfo newResult(ParsedProviderIntentInfo filter,
                 int match, int userId) {
             if (!sUserManager.exists(userId)) {
                 return null;
             }
-            final PackageParser.ProviderIntentInfo info = filter;
-            if (!sPackageManagerInternal.isEnabledAndMatches(info.provider.info, mFlags, userId)) {
+
+            ParsedProvider provider = null;
+
+            AndroidPackage pkg = sPackageManagerInternal.getPackage(filter.getPackageName());
+            if (pkg != null && pkg.getProviders() != null) {
+                for (ParsedProvider parsedProvider : pkg.getProviders()) {
+                    if (Objects.equals(parsedProvider.className, filter.getClassName())) {
+                        provider = parsedProvider;
+                    }
+                }
+            }
+
+            if (provider == null) {
                 return null;
             }
-            final PackageParser.Provider provider = info.provider;
-            PackageSetting ps = (PackageSetting) provider.owner.mExtras;
+
+            if (!sPackageManagerInternal.isEnabledAndMatches(provider, mFlags, userId)) {
+                return null;
+            }
+
+            PackageSetting ps = (PackageSetting) sPackageManagerInternal.getPackageSetting(
+                    filter.getPackageName());
             if (ps == null) {
                 return null;
             }
@@ -1527,7 +1657,7 @@
             final boolean isInstantApp = (mFlags & PackageManager.MATCH_INSTANT) != 0;
             // throw out filters that aren't visible to instant applications
             if (matchVisibleToInstantApp
-                    && !(info.isVisibleToInstantApp() || userState.instantApp)) {
+                    && !(filter.isVisibleToInstantApp() || userState.instantApp)) {
                 return null;
             }
             // throw out instant application filters if we're not explicitly requesting them
@@ -1539,8 +1669,8 @@
             if (userState.instantApp && ps.isUpdateAvailable()) {
                 return null;
             }
-            ProviderInfo pi = PackageParser.generateProviderInfo(provider, mFlags,
-                    userState, userId);
+            ProviderInfo pi = PackageInfoUtils.generateProviderInfo(pkg, provider,
+                    mFlags, userState, userId);
             if (pi == null) {
                 return null;
             }
@@ -1549,13 +1679,13 @@
             if ((mFlags & PackageManager.GET_RESOLVED_FILTER) != 0) {
                 res.filter = filter;
             }
-            res.priority = info.getPriority();
-            res.preferredOrder = provider.owner.mPreferredOrder;
+            res.priority = filter.getPriority();
+            res.preferredOrder = pkg.getPreferredOrder();
             res.match = match;
-            res.isDefault = info.hasDefault;
-            res.labelRes = info.labelRes;
-            res.nonLocalizedLabel = info.nonLocalizedLabel;
-            res.icon = info.icon;
+            res.isDefault = filter.hasDefault;
+            res.labelRes = filter.labelRes;
+            res.nonLocalizedLabel = filter.nonLocalizedLabel;
+            res.icon = filter.icon;
             res.system = res.providerInfo.applicationInfo.isSystemApp();
             return res;
         }
@@ -1567,26 +1697,37 @@
 
         @Override
         protected void dumpFilter(PrintWriter out, String prefix,
-                PackageParser.ProviderIntentInfo filter) {
+                ParsedProviderIntentInfo filter) {
+            ParsedProvider provider = null;
+
+            AndroidPackage pkg = sPackageManagerInternal.getPackage(filter.getPackageName());
+            if (pkg != null && pkg.getProviders() != null) {
+                for (ParsedProvider parsedProvider : pkg.getProviders()) {
+                    if (Objects.equals(parsedProvider.className, filter.getClassName())) {
+                        provider = parsedProvider;
+                    }
+                }
+            }
+
             out.print(prefix);
-            out.print(Integer.toHexString(System.identityHashCode(filter.provider)));
+            out.print(Integer.toHexString(System.identityHashCode(provider)));
             out.print(' ');
-            filter.provider.printComponentShortName(out);
+            ComponentName.printShortString(out, filter.getPackageName(), filter.getClassName());
             out.print(" filter ");
             out.println(Integer.toHexString(System.identityHashCode(filter)));
         }
 
         @Override
-        protected Object filterToLabel(PackageParser.ProviderIntentInfo filter) {
-            return filter.provider;
+        protected Object filterToLabel(ParsedProviderIntentInfo filter) {
+            return filter;
         }
 
         protected void dumpFilterLabel(PrintWriter out, String prefix, Object label, int count) {
-            final PackageParser.Provider provider = (PackageParser.Provider) label;
+            final ParsedProviderIntentInfo provider = (ParsedProviderIntentInfo) label;
             out.print(prefix);
             out.print(Integer.toHexString(System.identityHashCode(provider)));
             out.print(' ');
-            provider.printComponentShortName(out);
+            ComponentName.printShortString(out, provider.getPackageName(), provider.getClassName());
             if (count > 1) {
                 out.print(" (");
                 out.print(count);
@@ -1595,12 +1736,12 @@
             out.println();
         }
 
-        private final ArrayMap<ComponentName, PackageParser.Provider> mProviders = new ArrayMap<>();
+        private final ArrayMap<ComponentName, ParsedProvider> mProviders = new ArrayMap<>();
         private int mFlags;
     }
 
     private static final class ServiceIntentResolver
-            extends IntentResolver<PackageParser.ServiceIntentInfo, ResolveInfo> {
+            extends IntentResolver<ParsedServiceIntentInfo, ResolveInfo> {
         @Override
         public List<ResolveInfo> queryIntent(Intent intent, String resolvedType,
                 boolean defaultOnly, int userId) {
@@ -1618,22 +1759,22 @@
         }
 
         List<ResolveInfo> queryIntentForPackage(Intent intent, String resolvedType,
-                int flags, List<PackageParser.Service> packageServices, int userId) {
+                int flags, List<ParsedService> packageServices, int userId) {
             if (!sUserManager.exists(userId)) return null;
             if (packageServices == null) {
-                return null;
+                return Collections.emptyList();
             }
             mFlags = flags;
             final boolean defaultOnly = (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0;
             final int servicesSize = packageServices.size();
-            ArrayList<PackageParser.ServiceIntentInfo[]> listCut = new ArrayList<>(servicesSize);
+            ArrayList<ParsedServiceIntentInfo[]> listCut = new ArrayList<>(servicesSize);
 
-            ArrayList<PackageParser.ServiceIntentInfo> intentFilters;
+            List<ParsedServiceIntentInfo> intentFilters;
             for (int i = 0; i < servicesSize; ++i) {
                 intentFilters = packageServices.get(i).intents;
                 if (intentFilters != null && intentFilters.size() > 0) {
-                    PackageParser.ServiceIntentInfo[] array =
-                            new PackageParser.ServiceIntentInfo[intentFilters.size()];
+                    ParsedServiceIntentInfo[] array =
+                            new ParsedServiceIntentInfo[intentFilters.size()];
                     intentFilters.toArray(array);
                     listCut.add(array);
                 }
@@ -1641,40 +1782,40 @@
             return super.queryIntentFromList(intent, resolvedType, defaultOnly, listCut, userId);
         }
 
-        void addService(PackageParser.Service s) {
+        void addService(ParsedService s) {
             mServices.put(s.getComponentName(), s);
             if (DEBUG_SHOW_INFO) {
                 Log.v(TAG, "  "
-                        + (s.info.nonLocalizedLabel != null
-                        ? s.info.nonLocalizedLabel : s.info.name) + ":");
-                Log.v(TAG, "    Class=" + s.info.name);
+                        + (s.nonLocalizedLabel != null
+                        ? s.nonLocalizedLabel : s.getName()) + ":");
+                Log.v(TAG, "    Class=" + s.getName());
             }
             final int intentsSize = s.intents.size();
             int j;
             for (j = 0; j < intentsSize; j++) {
-                PackageParser.ServiceIntentInfo intent = s.intents.get(j);
+                ParsedServiceIntentInfo intent = s.intents.get(j);
                 if (DEBUG_SHOW_INFO) {
                     Log.v(TAG, "    IntentFilter:");
                     intent.dump(new LogPrinter(Log.VERBOSE, TAG), "      ");
                 }
                 if (!intent.debugCheck()) {
-                    Log.w(TAG, "==> For Service " + s.info.name);
+                    Log.w(TAG, "==> For Service " + s.getName());
                 }
                 addFilter(intent);
             }
         }
 
-        void removeService(PackageParser.Service s) {
+        void removeService(ParsedService s) {
             mServices.remove(s.getComponentName());
             if (DEBUG_SHOW_INFO) {
-                Log.v(TAG, "  " + (s.info.nonLocalizedLabel != null
-                        ? s.info.nonLocalizedLabel : s.info.name) + ":");
-                Log.v(TAG, "    Class=" + s.info.name);
+                Log.v(TAG, "  " + (s.nonLocalizedLabel != null
+                        ? s.nonLocalizedLabel : s.getName()) + ":");
+                Log.v(TAG, "    Class=" + s.getName());
             }
             final int intentsSize = s.intents.size();
             int j;
             for (j = 0; j < intentsSize; j++) {
-                PackageParser.ServiceIntentInfo intent = s.intents.get(j);
+                ParsedServiceIntentInfo intent = s.intents.get(j);
                 if (DEBUG_SHOW_INFO) {
                     Log.v(TAG, "    IntentFilter:");
                     intent.dump(new LogPrinter(Log.VERBOSE, TAG), "      ");
@@ -1685,12 +1826,11 @@
 
         @Override
         protected boolean allowFilterResult(
-                PackageParser.ServiceIntentInfo filter, List<ResolveInfo> dest) {
-            ServiceInfo filterSi = filter.service.info;
+                ParsedServiceIntentInfo filter, List<ResolveInfo> dest) {
             for (int i = dest.size() - 1; i >= 0; --i) {
                 ServiceInfo destAi = dest.get(i).serviceInfo;
-                if (destAi.name == filterSi.name
-                        && destAi.packageName == filterSi.packageName) {
+                if (Objects.equals(destAi.name, filter.getClassName())
+                        && Objects.equals(destAi.packageName, filter.getPackageName())) {
                     return false;
                 }
             }
@@ -1698,48 +1838,69 @@
         }
 
         @Override
-        protected PackageParser.ServiceIntentInfo[] newArray(int size) {
-            return new PackageParser.ServiceIntentInfo[size];
+        protected ParsedServiceIntentInfo[] newArray(int size) {
+            return new ParsedServiceIntentInfo[size];
         }
 
         @Override
-        protected boolean isFilterStopped(PackageParser.ServiceIntentInfo filter, int userId) {
+        protected boolean isFilterStopped(ParsedServiceIntentInfo filter, int userId) {
             if (!sUserManager.exists(userId)) return true;
-            PackageParser.Package p = filter.service.owner;
-            if (p != null) {
-                PackageSetting ps = (PackageSetting) p.mExtras;
-                if (ps != null) {
-                    // System apps are never considered stopped for purposes of
-                    // filtering, because there may be no way for the user to
-                    // actually re-launch them.
-                    return (ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0
-                            && ps.getStopped(userId);
-                }
+
+            AndroidPackage pkg = sPackageManagerInternal.getPackage(filter.getPackageName());
+            if (pkg == null) {
+                return false;
             }
-            return false;
+
+            PackageSetting ps = (PackageSetting) sPackageManagerInternal.getPackageSetting(
+                    filter.getPackageName());
+            if (ps == null) {
+                return false;
+            }
+
+            // System apps are never considered stopped for purposes of
+            // filtering, because there may be no way for the user to
+            // actually re-launch them.
+            return (ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0
+                    && ps.getStopped(userId);
         }
 
         @Override
         protected boolean isPackageForFilter(String packageName,
-                PackageParser.ServiceIntentInfo info) {
-            return packageName.equals(info.service.owner.packageName);
+                ParsedServiceIntentInfo info) {
+            return packageName.equals(info.getPackageName());
         }
 
         @Override
-        protected ResolveInfo newResult(PackageParser.ServiceIntentInfo filter,
+        protected ResolveInfo newResult(ParsedServiceIntentInfo filter,
                 int match, int userId) {
             if (!sUserManager.exists(userId)) return null;
-            final PackageParser.ServiceIntentInfo info = (PackageParser.ServiceIntentInfo) filter;
-            if (!sPackageManagerInternal.isEnabledAndMatches(info.service.info, mFlags, userId)) {
+
+            ParsedService service = null;
+
+            AndroidPackage pkg = sPackageManagerInternal.getPackage(filter.getPackageName());
+            if (pkg != null && pkg.getServices() != null) {
+                for (ParsedService parsedService : pkg.getServices()) {
+                    if (Objects.equals(parsedService.className, filter.getClassName())) {
+                        service = parsedService;
+                    }
+                }
+            }
+
+            if (service == null) {
                 return null;
             }
-            final PackageParser.Service service = info.service;
-            PackageSetting ps = (PackageSetting) service.owner.mExtras;
+
+            if (!sPackageManagerInternal.isEnabledAndMatches(service, mFlags, userId)) {
+                return null;
+            }
+
+            PackageSetting ps = (PackageSetting) sPackageManagerInternal.getPackageSetting(
+                    filter.getPackageName());
             if (ps == null) {
                 return null;
             }
             final PackageUserState userState = ps.readUserState(userId);
-            ServiceInfo si = PackageParser.generateServiceInfo(service, mFlags,
+            ServiceInfo si = PackageInfoUtils.generateServiceInfo(pkg, service, mFlags,
                     userState, userId);
             if (si == null) {
                 return null;
@@ -1749,7 +1910,7 @@
             final boolean isInstantApp = (mFlags & PackageManager.MATCH_INSTANT) != 0;
             // throw out filters that aren't visible to ephemeral apps
             if (matchVisibleToInstantApp
-                    && !(info.isVisibleToInstantApp() || userState.instantApp)) {
+                    && !(filter.isVisibleToInstantApp() || userState.instantApp)) {
                 return null;
             }
             // throw out ephemeral filters if we're not explicitly requesting them
@@ -1766,13 +1927,13 @@
             if ((mFlags & PackageManager.GET_RESOLVED_FILTER) != 0) {
                 res.filter = filter;
             }
-            res.priority = info.getPriority();
-            res.preferredOrder = service.owner.mPreferredOrder;
+            res.priority = filter.getPriority();
+            res.preferredOrder = pkg.getPreferredOrder();
             res.match = match;
-            res.isDefault = info.hasDefault;
-            res.labelRes = info.labelRes;
-            res.nonLocalizedLabel = info.nonLocalizedLabel;
-            res.icon = info.icon;
+            res.isDefault = filter.hasDefault;
+            res.labelRes = filter.labelRes;
+            res.nonLocalizedLabel = filter.nonLocalizedLabel;
+            res.icon = filter.icon;
             res.system = res.serviceInfo.applicationInfo.isSystemApp();
             return res;
         }
@@ -1784,31 +1945,42 @@
 
         @Override
         protected void dumpFilter(PrintWriter out, String prefix,
-                PackageParser.ServiceIntentInfo filter) {
+                ParsedServiceIntentInfo filter) {
+            ParsedService service = null;
+
+            AndroidPackage pkg = sPackageManagerInternal.getPackage(filter.getPackageName());
+            if (pkg != null && pkg.getServices() != null) {
+                for (ParsedService parsedService : pkg.getServices()) {
+                    if (Objects.equals(parsedService.className, filter.getClassName())) {
+                        service = parsedService;
+                    }
+                }
+            }
+
             out.print(prefix);
-            out.print(Integer.toHexString(System.identityHashCode(filter.service)));
+            out.print(Integer.toHexString(System.identityHashCode(service)));
             out.print(' ');
-            filter.service.printComponentShortName(out);
+            ComponentName.printShortString(out, filter.getPackageName(), filter.getClassName());
             out.print(" filter ");
             out.print(Integer.toHexString(System.identityHashCode(filter)));
-            if (filter.service.info.permission != null) {
-                out.print(" permission "); out.println(filter.service.info.permission);
+            if (service != null && service.getPermission() != null) {
+                out.print(" permission "); out.println(service.getPermission());
             } else {
                 out.println();
             }
         }
 
         @Override
-        protected Object filterToLabel(PackageParser.ServiceIntentInfo filter) {
-            return filter.service;
+        protected Object filterToLabel(ParsedServiceIntentInfo filter) {
+            return filter;
         }
 
         protected void dumpFilterLabel(PrintWriter out, String prefix, Object label, int count) {
-            final PackageParser.Service service = (PackageParser.Service) label;
+            final ParsedServiceIntentInfo service = (ParsedServiceIntentInfo) label;
             out.print(prefix);
             out.print(Integer.toHexString(System.identityHashCode(service)));
             out.print(' ');
-            service.printComponentShortName(out);
+            ComponentName.printShortString(out, service.getPackageName(), service.getClassName());
             if (count > 1) {
                 out.print(" ("); out.print(count); out.print(" filters)");
             }
@@ -1816,7 +1988,7 @@
         }
 
         // Keys are String (activity class name), values are Activity.
-        private final ArrayMap<ComponentName, PackageParser.Service> mServices = new ArrayMap<>();
+        private final ArrayMap<ComponentName, ParsedService> mServices = new ArrayMap<>();
         private int mFlags;
     }
 
@@ -1905,7 +2077,7 @@
 
     /** Generic to create an {@link Iterator} for a data type */
     static class IterGenerator<E> {
-        public Iterator<E> generate(ActivityIntentInfo info) {
+        public Iterator<E> generate(ParsedActivityIntentInfo info) {
             return null;
         }
     }
@@ -1913,7 +2085,7 @@
     /** Create an {@link Iterator} for intent actions */
     static class ActionIterGenerator extends IterGenerator<String> {
         @Override
-        public Iterator<String> generate(ActivityIntentInfo info) {
+        public Iterator<String> generate(ParsedActivityIntentInfo info) {
             return info.actionsIterator();
         }
     }
@@ -1921,7 +2093,7 @@
     /** Create an {@link Iterator} for intent categories */
     static class CategoriesIterGenerator extends IterGenerator<String> {
         @Override
-        public Iterator<String> generate(ActivityIntentInfo info) {
+        public Iterator<String> generate(ParsedActivityIntentInfo info) {
             return info.categoriesIterator();
         }
     }
@@ -1929,7 +2101,7 @@
     /** Create an {@link Iterator} for intent schemes */
     static class SchemesIterGenerator extends IterGenerator<String> {
         @Override
-        public Iterator<String> generate(ActivityIntentInfo info) {
+        public Iterator<String> generate(ParsedActivityIntentInfo info) {
             return info.schemesIterator();
         }
     }
@@ -1937,9 +2109,39 @@
     /** Create an {@link Iterator} for intent authorities */
     static class AuthoritiesIterGenerator extends IterGenerator<IntentFilter.AuthorityEntry> {
         @Override
-        public Iterator<IntentFilter.AuthorityEntry> generate(ActivityIntentInfo info) {
+        public Iterator<IntentFilter.AuthorityEntry> generate(ParsedActivityIntentInfo info) {
             return info.authoritiesIterator();
         }
     }
 
+    // TODO(b/135203078): Document or remove this if possible.
+    class EffectiveProvider extends ParsedProvider {
+
+        private String mEffectiveAuthority;
+        private boolean mEffectiveSyncable;
+
+        public EffectiveProvider(ParsedProvider parsedProvider) {
+            this.setFrom(parsedProvider);
+            this.mEffectiveAuthority = parsedProvider.getAuthority();
+            this.mEffectiveSyncable = parsedProvider.isSyncable();
+        }
+
+        public void setEffectiveAuthority(String authority) {
+            this.mEffectiveAuthority = authority;
+        }
+
+        public void setEffectiveSyncable(boolean syncable) {
+            this.mEffectiveSyncable = syncable;
+        }
+
+        @Override
+        public String getAuthority() {
+            return mEffectiveAuthority;
+        }
+
+        @Override
+        public boolean isSyncable() {
+            return mEffectiveSyncable;
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/pm/InstantAppRegistry.java b/services/core/java/com/android/server/pm/InstantAppRegistry.java
index 9e04c4b..f9113fa 100644
--- a/services/core/java/com/android/server/pm/InstantAppRegistry.java
+++ b/services/core/java/com/android/server/pm/InstantAppRegistry.java
@@ -20,9 +20,11 @@
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.content.Intent;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.InstantAppInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageParser;
+import android.content.pm.parsing.AndroidPackage;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.graphics.Canvas;
@@ -137,7 +139,7 @@
     public byte[] getInstantAppCookieLPw(@NonNull String packageName,
             @UserIdInt int userId) {
         // Only installed packages can get their own cookie
-        PackageParser.Package pkg = mService.mPackages.get(packageName);
+        AndroidPackage pkg = mService.mPackages.get(packageName);
         if (pkg == null) {
             return null;
         }
@@ -171,7 +173,7 @@
         }
 
         // Only an installed package can set its own cookie
-        PackageParser.Package pkg = mService.mPackages.get(packageName);
+        AndroidPackage pkg = mService.mPackages.get(packageName);
         if (pkg == null) {
             return false;
         }
@@ -264,15 +266,15 @@
     }
 
     @GuardedBy("mService.mLock")
-    public void onPackageInstalledLPw(@NonNull PackageParser.Package pkg, @NonNull int[] userIds) {
-        PackageSetting ps = (PackageSetting) pkg.mExtras;
+    public void onPackageInstalledLPw(@NonNull AndroidPackage pkg, @NonNull int[] userIds) {
+        PackageSetting ps = mService.getPackageSetting(pkg.getPackageName());
         if (ps == null) {
             return;
         }
 
         for (int userId : userIds) {
             // Ignore not installed apps
-            if (mService.mPackages.get(pkg.packageName) == null || !ps.getInstalled(userId)) {
+            if (mService.mPackages.get(pkg.getPackageName()) == null || !ps.getInstalled(userId)) {
                 continue;
             }
 
@@ -286,16 +288,16 @@
 
             // Remove the in-memory state
             removeUninstalledInstantAppStateLPw((UninstalledInstantAppState state) ->
-                            state.mInstantAppInfo.getPackageName().equals(pkg.packageName),
+                            state.mInstantAppInfo.getPackageName().equals(pkg.getPackageName()),
                     userId);
 
             // Remove the on-disk state except the cookie
-            File instantAppDir = getInstantApplicationDir(pkg.packageName, userId);
+            File instantAppDir = getInstantApplicationDir(pkg.getPackageName(), userId);
             new File(instantAppDir, INSTANT_APP_METADATA_FILE).delete();
             new File(instantAppDir, INSTANT_APP_ICON_FILE).delete();
 
             // If app signature changed - wipe the cookie
-            File currentCookieFile = peekInstantCookieFile(pkg.packageName, userId);
+            File currentCookieFile = peekInstantCookieFile(pkg.getPackageName(), userId);
             if (currentCookieFile == null) {
                 continue;
             }
@@ -310,7 +312,7 @@
             // We prefer the modern computation procedure where all certs are taken
             // into account but also allow the value from the old computation to avoid
             // data loss.
-            if (pkg.mSigningDetails.checkCapability(currentCookieSha256,
+            if (pkg.getSigningDetails().checkCapability(currentCookieSha256,
                     PackageParser.SigningDetails.CertCapabilities.INSTALLED_DATA)) {
                 return;
             }
@@ -318,7 +320,7 @@
             // For backwards compatibility we accept match based on any signature, since we may have
             // recorded only the first for multiply-signed packages
             final String[] signaturesSha256Digests =
-                    PackageUtils.computeSignaturesSha256Digests(pkg.mSigningDetails.signatures);
+                    PackageUtils.computeSignaturesSha256Digests(pkg.getSigningDetails().signatures);
             for (String s : signaturesSha256Digests) {
                 if (s.equals(currentCookieSha256)) {
                     return;
@@ -326,7 +328,7 @@
             }
 
             // Sorry, you are out of luck - different signatures - nuke data
-            Slog.i(LOG_TAG, "Signature for package " + pkg.packageName
+            Slog.i(LOG_TAG, "Signature for package " + pkg.getPackageName()
                     + " changed - dropping cookie");
                 // Make sure a pending write for the old signed app is cancelled
             mCookiePersistence.cancelPendingPersistLPw(pkg, userId);
@@ -335,15 +337,15 @@
     }
 
     @GuardedBy("mService.mLock")
-    public void onPackageUninstalledLPw(@NonNull PackageParser.Package pkg,
+    public void onPackageUninstalledLPw(@NonNull AndroidPackage pkg,
             @NonNull int[] userIds) {
-        PackageSetting ps = (PackageSetting) pkg.mExtras;
+        PackageSetting ps = mService.getPackageSetting(pkg.getPackageName());
         if (ps == null) {
             return;
         }
 
         for (int userId : userIds) {
-            if (mService.mPackages.get(pkg.packageName) != null && ps.getInstalled(userId)) {
+            if (mService.mPackages.get(pkg.getPackageName()) != null && ps.getInstalled(userId)) {
                 continue;
             }
 
@@ -353,7 +355,7 @@
                 removeInstantAppLPw(userId, ps.appId);
             } else {
                 // Deleting an app prunes all instant state such as cookie
-                deleteDir(getInstantApplicationDir(pkg.packageName, userId));
+                deleteDir(getInstantApplicationDir(pkg.getPackageName(), userId));
                 mCookiePersistence.cancelPendingPersistLPw(pkg, userId);
                 removeAppLPw(userId, ps.appId);
             }
@@ -487,7 +489,7 @@
     }
 
     @GuardedBy("mService.mLock")
-    private void addUninstalledInstantAppLPw(@NonNull PackageParser.Package pkg,
+    private void addUninstalledInstantAppLPw(@NonNull AndroidPackage pkg,
             @UserIdInt int userId) {
         InstantAppInfo uninstalledApp = createInstantAppInfoForPackage(
                 pkg, userId, false);
@@ -511,14 +513,15 @@
         writeInstantApplicationIconLPw(pkg, userId);
     }
 
-    private void writeInstantApplicationIconLPw(@NonNull PackageParser.Package pkg,
+    private void writeInstantApplicationIconLPw(@NonNull AndroidPackage pkg,
             @UserIdInt int userId) {
-        File appDir = getInstantApplicationDir(pkg.packageName, userId);
+        File appDir = getInstantApplicationDir(pkg.getPackageName(), userId);
         if (!appDir.exists()) {
             return;
         }
 
-        Drawable icon = pkg.applicationInfo.loadIcon(mService.mContext.getPackageManager());
+        // TODO(b/135203078): Remove toAppInfo call? Requires significant additions/changes to PM
+        Drawable icon = pkg.toAppInfo().loadIcon(mService.mContext.getPackageManager());
 
         final Bitmap bitmap;
         if (icon instanceof BitmapDrawable) {
@@ -531,7 +534,7 @@
             icon.draw(canvas);
         }
 
-        File iconFile = new File(getInstantApplicationDir(pkg.packageName, userId),
+        File iconFile = new File(getInstantApplicationDir(pkg.getPackageName(), userId),
                 INSTANT_APP_ICON_FILE);
 
         try (FileOutputStream out = new FileOutputStream(iconFile)) {
@@ -690,14 +693,16 @@
 
             final int packageCount = mService.mPackages.size();
             for (int i = 0; i < packageCount; i++) {
-                final PackageParser.Package pkg = mService.mPackages.valueAt(i);
+                final AndroidPackage pkg = mService.mPackages.valueAt(i);
                 if (now - pkg.getLatestPackageUseTimeInMills() < maxInstalledCacheDuration) {
                     continue;
                 }
-                if (!(pkg.mExtras instanceof PackageSetting)) {
+
+                final PackageSetting ps = mService.getPackageSetting(pkg.getPackageName());
+                if (ps == null) {
                     continue;
                 }
-                final PackageSetting  ps = (PackageSetting) pkg.mExtras;
+
                 boolean installedOnlyAsInstantApp = false;
                 for (int userId : allUsers) {
                     if (ps.getInstalled(userId)) {
@@ -713,14 +718,14 @@
                     if (packagesToDelete == null) {
                         packagesToDelete = new ArrayList<>();
                     }
-                    packagesToDelete.add(pkg.packageName);
+                    packagesToDelete.add(pkg.getPackageName());
                 }
             }
 
             if (packagesToDelete != null) {
                 packagesToDelete.sort((String lhs, String rhs) -> {
-                    final PackageParser.Package lhsPkg = mService.mPackages.get(lhs);
-                    final PackageParser.Package rhsPkg = mService.mPackages.get(rhs);
+                    final AndroidPackage lhsPkg = mService.mPackages.get(lhs);
+                    final AndroidPackage rhsPkg = mService.mPackages.get(rhs);
                     if (lhsPkg == null && rhsPkg == null) {
                         return 0;
                     } else if (lhsPkg == null) {
@@ -735,18 +740,23 @@
                                 rhsPkg.getLatestPackageUseTimeInMills()) {
                             return -1;
                         } else {
-                            if (lhsPkg.mExtras instanceof PackageSetting
-                                    && rhsPkg.mExtras instanceof PackageSetting) {
-                                final PackageSetting lhsPs = (PackageSetting) lhsPkg.mExtras;
-                                final PackageSetting rhsPs = (PackageSetting) rhsPkg.mExtras;
-                                if (lhsPs.firstInstallTime > rhsPs.firstInstallTime) {
-                                    return 1;
-                                } else {
-                                    return -1;
-                                }
-                            } else {
+                            final PackageSetting lhsPs = mService.getPackageSetting(
+                                    lhsPkg.getPackageName());
+                            if (lhsPs == null) {
                                 return 0;
                             }
+
+                            final PackageSetting rhsPs = mService.getPackageSetting(
+                                    rhsPkg.getPackageName());
+                            if (rhsPs == null) {
+                                return 0;
+                            }
+
+                            if (lhsPs.firstInstallTime > rhsPs.firstInstallTime) {
+                                return 1;
+                            } else {
+                                return -1;
+                            }
                         }
                     }
                 });
@@ -818,8 +828,8 @@
 
         final int packageCount = mService.mPackages.size();
         for (int i = 0; i < packageCount; i++) {
-            final PackageParser.Package pkg = mService.mPackages.valueAt(i);
-            final PackageSetting ps = (PackageSetting) pkg.mExtras;
+            final AndroidPackage pkg = mService.mPackages.valueAt(i);
+            final PackageSetting ps = mService.getPackageSetting(pkg.getPackageName());
             if (ps == null || !ps.getInstantApp(userId)) {
                 continue;
             }
@@ -839,9 +849,9 @@
 
     private @NonNull
     InstantAppInfo createInstantAppInfoForPackage(
-            @NonNull PackageParser.Package pkg, @UserIdInt int userId,
+            @NonNull AndroidPackage pkg, @UserIdInt int userId,
             boolean addApplicationInfo) {
-        PackageSetting ps = (PackageSetting) pkg.mExtras;
+        PackageSetting ps = mService.getPackageSetting(pkg.getPackageName());
         if (ps == null) {
             return null;
         }
@@ -849,19 +859,20 @@
             return null;
         }
 
-        String[] requestedPermissions = new String[pkg.requestedPermissions.size()];
-        pkg.requestedPermissions.toArray(requestedPermissions);
+        String[] requestedPermissions = new String[pkg.getRequestedPermissions().size()];
+        pkg.getRequestedPermissions().toArray(requestedPermissions);
 
         Set<String> permissions = ps.getPermissionsState().getPermissions(userId);
         String[] grantedPermissions = new String[permissions.size()];
         permissions.toArray(grantedPermissions);
 
+        ApplicationInfo appInfo = pkg.toAppInfo();
         if (addApplicationInfo) {
-            return new InstantAppInfo(pkg.applicationInfo,
+            return new InstantAppInfo(appInfo,
                     requestedPermissions, grantedPermissions);
         } else {
-            return new InstantAppInfo(pkg.applicationInfo.packageName,
-                    pkg.applicationInfo.loadLabel(mService.mContext.getPackageManager()),
+            return new InstantAppInfo(appInfo.packageName,
+                    appInfo.loadLabel(mService.mContext.getPackageManager()),
                     requestedPermissions, grantedPermissions);
         }
     }
@@ -887,10 +898,10 @@
         return uninstalledApps;
     }
 
-    private void propagateInstantAppPermissionsIfNeeded(@NonNull PackageParser.Package pkg,
+    private void propagateInstantAppPermissionsIfNeeded(@NonNull AndroidPackage pkg,
             @UserIdInt int userId) {
         InstantAppInfo appInfo = peekOrParseUninstalledInstantAppInfo(
-                pkg.packageName, userId);
+                pkg.getPackageName(), userId);
         if (appInfo == null) {
             return;
         }
@@ -902,8 +913,10 @@
             for (String grantedPermission : appInfo.getGrantedPermissions()) {
                 final boolean propagatePermission =
                         mService.mSettings.canPropagatePermissionToInstantApp(grantedPermission);
-                if (propagatePermission && pkg.requestedPermissions.contains(grantedPermission)) {
-                    mService.grantRuntimePermission(pkg.packageName, grantedPermission, userId);
+                if (propagatePermission && pkg.getRequestedPermissions().contains(
+                        grantedPermission)) {
+                    mService.grantRuntimePermission(pkg.getPackageName(), grantedPermission,
+                            userId);
                 }
             }
         } finally {
@@ -1188,18 +1201,19 @@
             super(looper);
         }
 
-        public void schedulePersistLPw(@UserIdInt int userId, @NonNull PackageParser.Package pkg,
+        public void schedulePersistLPw(@UserIdInt int userId, @NonNull AndroidPackage pkg,
                 @NonNull byte[] cookie) {
             // Before we used only the first signature to compute the SHA 256 but some
             // apps could be singed by multiple certs and the cert order is undefined.
             // We prefer the modern computation procedure where all certs are taken
             // into account and delete the file derived via the legacy hash computation.
-            File newCookieFile = computeInstantCookieFile(pkg.packageName,
-                    PackageUtils.computeSignaturesSha256Digest(pkg.mSigningDetails.signatures), userId);
-            if (!pkg.mSigningDetails.hasSignatures()) {
+            File newCookieFile = computeInstantCookieFile(pkg.getPackageName(),
+                    PackageUtils.computeSignaturesSha256Digest(pkg.getSigningDetails().signatures),
+                    userId);
+            if (!pkg.getSigningDetails().hasSignatures()) {
                 Slog.wtf(LOG_TAG, "Parsed Instant App contains no valid signatures!");
             }
-            File oldCookieFile = peekInstantCookieFile(pkg.packageName, userId);
+            File oldCookieFile = peekInstantCookieFile(pkg.getPackageName(), userId);
             if (oldCookieFile != null && !newCookieFile.equals(oldCookieFile)) {
                 oldCookieFile.delete();
             }
@@ -1209,12 +1223,12 @@
                     PERSIST_COOKIE_DELAY_MILLIS);
         }
 
-        public @Nullable byte[] getPendingPersistCookieLPr(@NonNull PackageParser.Package pkg,
+        public @Nullable byte[] getPendingPersistCookieLPr(@NonNull AndroidPackage pkg,
                 @UserIdInt int userId) {
             ArrayMap<String, SomeArgs> pendingWorkForUser =
                     mPendingPersistCookies.get(userId);
             if (pendingWorkForUser != null) {
-                SomeArgs state = pendingWorkForUser.get(pkg.packageName);
+                SomeArgs state = pendingWorkForUser.get(pkg.getPackageName());
                 if (state != null) {
                     return (byte[]) state.arg1;
                 }
@@ -1222,7 +1236,7 @@
             return null;
         }
 
-        public void cancelPendingPersistLPw(@NonNull PackageParser.Package pkg,
+        public void cancelPendingPersistLPw(@NonNull AndroidPackage pkg,
                 @UserIdInt int userId) {
             removeMessages(userId, pkg);
             SomeArgs state = removePendingPersistCookieLPr(pkg, userId);
@@ -1232,7 +1246,7 @@
         }
 
         private void addPendingPersistCookieLPw(@UserIdInt int userId,
-                @NonNull PackageParser.Package pkg, @NonNull byte[] cookie,
+                @NonNull AndroidPackage pkg, @NonNull byte[] cookie,
                 @NonNull File cookieFile) {
             ArrayMap<String, SomeArgs> pendingWorkForUser =
                     mPendingPersistCookies.get(userId);
@@ -1243,16 +1257,16 @@
             SomeArgs args = SomeArgs.obtain();
             args.arg1 = cookie;
             args.arg2 = cookieFile;
-            pendingWorkForUser.put(pkg.packageName, args);
+            pendingWorkForUser.put(pkg.getPackageName(), args);
         }
 
-        private SomeArgs removePendingPersistCookieLPr(@NonNull PackageParser.Package pkg,
+        private SomeArgs removePendingPersistCookieLPr(@NonNull AndroidPackage pkg,
                 @UserIdInt int userId) {
             ArrayMap<String, SomeArgs> pendingWorkForUser =
                     mPendingPersistCookies.get(userId);
             SomeArgs state = null;
             if (pendingWorkForUser != null) {
-                state = pendingWorkForUser.remove(pkg.packageName);
+                state = pendingWorkForUser.remove(pkg.getPackageName());
                 if (pendingWorkForUser.isEmpty()) {
                     mPendingPersistCookies.remove(userId);
                 }
@@ -1263,7 +1277,7 @@
         @Override
         public void handleMessage(Message message) {
             int userId = message.what;
-            PackageParser.Package pkg = (PackageParser.Package) message.obj;
+            AndroidPackage pkg = (AndroidPackage) message.obj;
             SomeArgs state = removePendingPersistCookieLPr(pkg, userId);
             if (state == null) {
                 return;
@@ -1271,7 +1285,7 @@
             byte[] cookie = (byte[]) state.arg1;
             File cookieFile = (File) state.arg2;
             state.recycle();
-            persistInstantApplicationCookie(cookie, pkg.packageName, cookieFile, userId);
+            persistInstantApplicationCookie(cookie, pkg.getPackageName(), cookieFile, userId);
         }
     }
 }
diff --git a/services/core/java/com/android/server/pm/InstructionSets.java b/services/core/java/com/android/server/pm/InstructionSets.java
index ec48713..0a065eb 100644
--- a/services/core/java/com/android/server/pm/InstructionSets.java
+++ b/services/core/java/com/android/server/pm/InstructionSets.java
@@ -16,7 +16,7 @@
 
 package com.android.server.pm;
 
-import android.content.pm.ApplicationInfo;
+import android.content.pm.parsing.AndroidPackage;
 import android.os.Build;
 import android.os.SystemProperties;
 import android.text.TextUtils;
@@ -35,30 +35,16 @@
 public class InstructionSets {
     private static final String PREFERRED_INSTRUCTION_SET =
             VMRuntime.getInstructionSet(Build.SUPPORTED_ABIS[0]);
-    public static String[] getAppDexInstructionSets(ApplicationInfo info) {
-        if (info.primaryCpuAbi != null) {
-            if (info.secondaryCpuAbi != null) {
+
+    public static String[] getAppDexInstructionSets(String primaryCpuAbi, String secondaryCpuAbi) {
+        if (primaryCpuAbi != null) {
+            if (secondaryCpuAbi != null) {
                 return new String[] {
-                        VMRuntime.getInstructionSet(info.primaryCpuAbi),
-                        VMRuntime.getInstructionSet(info.secondaryCpuAbi) };
+                        VMRuntime.getInstructionSet(primaryCpuAbi),
+                        VMRuntime.getInstructionSet(secondaryCpuAbi) };
             } else {
                 return new String[] {
-                        VMRuntime.getInstructionSet(info.primaryCpuAbi) };
-            }
-        }
-
-        return new String[] { getPreferredInstructionSet() };
-    }
-
-    public static String[] getAppDexInstructionSets(PackageSetting ps) {
-        if (ps.primaryCpuAbiString != null) {
-            if (ps.secondaryCpuAbiString != null) {
-                return new String[] {
-                        VMRuntime.getInstructionSet(ps.primaryCpuAbiString),
-                        VMRuntime.getInstructionSet(ps.secondaryCpuAbiString) };
-            } else {
-                return new String[] {
-                        VMRuntime.getInstructionSet(ps.primaryCpuAbiString) };
+                        VMRuntime.getInstructionSet(primaryCpuAbi) };
             }
         }
 
@@ -124,4 +110,12 @@
         return VMRuntime.getInstructionSet(abis.primary);
     }
 
+    public static String getPrimaryInstructionSet(AndroidPackage pkg) {
+        if (pkg.getPrimaryCpuAbi() == null) {
+            return getPreferredInstructionSet();
+        }
+
+        return VMRuntime.getInstructionSet(pkg.getPrimaryCpuAbi());
+    }
+
 }
diff --git a/services/core/java/com/android/server/pm/IntentFilterVerificationState.java b/services/core/java/com/android/server/pm/IntentFilterVerificationState.java
index a4e9d10..c97d85d 100644
--- a/services/core/java/com/android/server/pm/IntentFilterVerificationState.java
+++ b/services/core/java/com/android/server/pm/IntentFilterVerificationState.java
@@ -17,7 +17,7 @@
 package com.android.server.pm;
 
 import android.content.pm.PackageManager;
-import android.content.pm.PackageParser;
+import android.content.pm.parsing.ComponentParseUtils;
 import android.util.ArraySet;
 import android.util.Slog;
 
@@ -35,7 +35,7 @@
 
     private int mState;
 
-    private ArrayList<PackageParser.ActivityIntentInfo> mFilters = new ArrayList<>();
+    private ArrayList<ComponentParseUtils.ParsedActivityIntentInfo> mFilters = new ArrayList<>();
     private ArraySet<String> mHosts = new ArraySet<>();
     private int mUserId;
 
@@ -66,7 +66,7 @@
         setState(STATE_VERIFICATION_PENDING);
     }
 
-    public ArrayList<PackageParser.ActivityIntentInfo> getFilters() {
+    public ArrayList<ComponentParseUtils.ParsedActivityIntentInfo> getFilters() {
         return mFilters;
     }
 
@@ -123,7 +123,7 @@
         return false;
     }
 
-    public void addFilter(PackageParser.ActivityIntentInfo filter) {
+    public void addFilter(ComponentParseUtils.ParsedActivityIntentInfo filter) {
         mFilters.add(filter);
         mHosts.addAll(filter.getHostsList());
     }
diff --git a/services/core/java/com/android/server/pm/KeySetManagerService.java b/services/core/java/com/android/server/pm/KeySetManagerService.java
index 93d3b77..70c0f8d 100644
--- a/services/core/java/com/android/server/pm/KeySetManagerService.java
+++ b/services/core/java/com/android/server/pm/KeySetManagerService.java
@@ -20,23 +20,26 @@
 
 import static com.android.server.pm.PackageManagerService.SCAN_INITIAL;
 
-import com.android.internal.util.Preconditions;
 import android.content.pm.PackageParser;
+import android.content.pm.parsing.AndroidPackage;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Base64;
-import android.util.Slog;
 import android.util.LongSparseArray;
+import android.util.Slog;
 
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.security.PublicKey;
-import java.util.Set;
+import com.android.internal.util.Preconditions;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
 
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.security.PublicKey;
+import java.util.Map;
+import java.util.Set;
+
 /*
  * Manages system-wide KeySet state.
  */
@@ -182,33 +185,31 @@
      *
      * Returns true if the package can safely be added to the keyset metadata.
      */
-    public void assertScannedPackageValid(PackageParser.Package pkg)
+    public void assertScannedPackageValid(AndroidPackage pkg)
             throws PackageManagerException {
-        if (pkg == null || pkg.packageName == null) {
+        if (pkg == null || pkg.getPackageName() == null) {
             throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
                     "Passed invalid package to keyset validation.");
         }
-        ArraySet<PublicKey> signingKeys = pkg.mSigningDetails.publicKeys;
+        ArraySet<PublicKey> signingKeys = pkg.getSigningDetails().publicKeys;
         if (signingKeys == null || !(signingKeys.size() > 0) || signingKeys.contains(null)) {
             throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
                     "Package has invalid signing-key-set.");
         }
-        ArrayMap<String, ArraySet<PublicKey>> definedMapping = pkg.mKeySetMapping;
+        Map<String, ArraySet<PublicKey>> definedMapping = pkg.getKeySetMapping();
         if (definedMapping != null) {
             if (definedMapping.containsKey(null) || definedMapping.containsValue(null)) {
                 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
                         "Package has null defined key set.");
             }
-            int defMapSize = definedMapping.size();
-            for (int i = 0; i < defMapSize; i++) {
-                if (!(definedMapping.valueAt(i).size() > 0)
-                        || definedMapping.valueAt(i).contains(null)) {
+            for (ArraySet<PublicKey> value : definedMapping.values()) {
+                if (!(value.size() > 0) || value.contains(null)) {
                     throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
                             "Package has null/no public keys for defined key-sets.");
                 }
             }
         }
-        ArraySet<String> upgradeAliases = pkg.mUpgradeKeySets;
+        Set<String> upgradeAliases = pkg.getUpgradeKeySets();
         if (upgradeAliases != null) {
             if (definedMapping == null || !(definedMapping.keySet().containsAll(upgradeAliases))) {
                 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
@@ -217,17 +218,17 @@
         }
     }
 
-    public void addScannedPackageLPw(PackageParser.Package pkg) {
+    public void addScannedPackageLPw(AndroidPackage pkg) {
         Preconditions.checkNotNull(pkg, "Attempted to add null pkg to ksms.");
-        Preconditions.checkNotNull(pkg.packageName, "Attempted to add null pkg to ksms.");
-        PackageSetting ps = mPackages.get(pkg.packageName);
-        Preconditions.checkNotNull(ps, "pkg: " + pkg.packageName
+        Preconditions.checkNotNull(pkg.getPackageName(), "Attempted to add null pkg to ksms.");
+        PackageSetting ps = mPackages.get(pkg.getPackageName());
+        Preconditions.checkNotNull(ps, "pkg: " + pkg.getPackageName()
                     + "does not have a corresponding entry in mPackages.");
-        addSigningKeySetToPackageLPw(ps, pkg.mSigningDetails.publicKeys);
-        if (pkg.mKeySetMapping != null) {
-            addDefinedKeySetsToPackageLPw(ps, pkg.mKeySetMapping);
-            if (pkg.mUpgradeKeySets != null) {
-                addUpgradeKeySetsToPackageLPw(ps, pkg.mUpgradeKeySets);
+        addSigningKeySetToPackageLPw(ps, pkg.getSigningDetails().publicKeys);
+        if (pkg.getKeySetMapping() != null) {
+            addDefinedKeySetsToPackageLPw(ps, pkg.getKeySetMapping());
+            if (pkg.getUpgradeKeySets() != null) {
+                addUpgradeKeySetsToPackageLPw(ps, pkg.getUpgradeKeySets());
             }
         }
     }
@@ -280,15 +281,14 @@
      * Remove any KeySets the package no longer defines.
      */
     void addDefinedKeySetsToPackageLPw(PackageSetting pkg,
-            ArrayMap<String, ArraySet<PublicKey>> definedMapping) {
+            Map<String, ArraySet<PublicKey>> definedMapping) {
         ArrayMap<String, Long> prevDefinedKeySets = pkg.keySetData.getAliases();
 
         /* add all of the newly defined KeySets */
-        ArrayMap<String, Long> newKeySetAliases = new ArrayMap<String, Long>();
-        final int defMapSize = definedMapping.size();
-        for (int i = 0; i < defMapSize; i++) {
-            String alias = definedMapping.keyAt(i);
-            ArraySet<PublicKey> pubKeys = definedMapping.valueAt(i);
+        Map<String, Long> newKeySetAliases = new ArrayMap<>();
+        for (Map.Entry<String, ArraySet<PublicKey>> entry : definedMapping.entrySet()) {
+            String alias = entry.getKey();
+            ArraySet<PublicKey> pubKeys = entry.getValue();
             if (alias != null && pubKeys != null && pubKeys.size() > 0) {
                 KeySetHandle ks = addKeySetLPw(pubKeys);
                 newKeySetAliases.put(alias, ks.getId());
@@ -313,12 +313,10 @@
      * after all of the defined KeySets have been added.
      */
     void addUpgradeKeySetsToPackageLPw(PackageSetting pkg,
-            ArraySet<String> upgradeAliases) {
-        final int uaSize = upgradeAliases.size();
-        for (int i = 0; i < uaSize; i++) {
-            pkg.keySetData.addUpgradeKeySet(upgradeAliases.valueAt(i));
+            Set<String> upgradeAliases) {
+        for (String upgradeAlias : upgradeAliases) {
+            pkg.keySetData.addUpgradeKeySet(upgradeAlias);
         }
-        return;
     }
 
     /**
@@ -364,14 +362,14 @@
         return true;
     }
 
-    public boolean checkUpgradeKeySetLocked(PackageSettingBase oldPS,
-            PackageParser.Package newPkg) {
+    public boolean checkUpgradeKeySetLocked(PackageSettingBase oldPS, AndroidPackage pkg) {
         // Upgrade keysets are being used.  Determine if new package has a superset of the
         // required keys.
         long[] upgradeKeySets = oldPS.keySetData.getUpgradeKeySets();
         for (int i = 0; i < upgradeKeySets.length; i++) {
             Set<PublicKey> upgradeSet = getPublicKeysFromKeySetLPr(upgradeKeySets[i]);
-            if (upgradeSet != null && newPkg.mSigningDetails.publicKeys.containsAll(upgradeSet)) {
+            if (upgradeSet != null
+                    && pkg.getSigningDetails().publicKeys.containsAll(upgradeSet)) {
                 return true;
             }
         }
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index f7fd1b2..673e265 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -40,13 +40,13 @@
 import android.content.pm.PackageInstaller.SessionInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
-import android.content.pm.PackageParser;
 import android.content.pm.ParceledListSlice;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ShortcutInfo;
 import android.content.pm.ShortcutServiceInternal;
 import android.content.pm.ShortcutServiceInternal.ShortcutChangeListener;
 import android.content.pm.UserInfo;
+import android.content.pm.parsing.AndroidPackage;
 import android.graphics.Rect;
 import android.net.Uri;
 import android.os.Binder;
@@ -447,7 +447,7 @@
             }
             final PackageManagerInternal pmInt =
                     LocalServices.getService(PackageManagerInternal.class);
-            final PackageParser.Package pkg = pmInt.getPackage(appInfo.packageName);
+            final AndroidPackage pkg = pmInt.getPackage(appInfo.packageName);
             if (pkg == null) {
                 // Should not happen, but we shouldn't be failing if it does
                 return false;
@@ -458,8 +458,8 @@
                     appInfo.packageName);
         }
 
-        private boolean requestsPermissions(@NonNull PackageParser.Package pkg) {
-            return !ArrayUtils.isEmpty(pkg.requestedPermissions);
+        private boolean requestsPermissions(@NonNull AndroidPackage pkg) {
+            return !ArrayUtils.isEmpty(pkg.getRequestedPermissions());
         }
 
         private boolean hasDefaultEnableLauncherActivity(@NonNull String packageName) {
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index d49ecdd..ae7a4a7 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -22,7 +22,7 @@
 import android.annotation.Nullable;
 import android.content.Context;
 import android.content.pm.IOtaDexopt;
-import android.content.pm.PackageParser;
+import android.content.pm.parsing.AndroidPackage;
 import android.os.Environment;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
@@ -118,8 +118,8 @@
         if (mDexoptCommands != null) {
             throw new IllegalStateException("already called prepare()");
         }
-        final List<PackageParser.Package> important;
-        final List<PackageParser.Package> others;
+        final List<AndroidPackage> important;
+        final List<AndroidPackage> others;
         synchronized (mPackageManagerService.mLock) {
             // Important: the packages we need to run with ab-ota compiler-reason.
             important = PackageManagerServiceUtils.getPackagesForDexopt(
@@ -133,12 +133,12 @@
             mDexoptCommands = new ArrayList<>(3 * mPackageManagerService.mPackages.size() / 2);
         }
 
-        for (PackageParser.Package p : important) {
+        for (AndroidPackage p : important) {
             mDexoptCommands.addAll(generatePackageDexopts(p, PackageManagerService.REASON_AB_OTA));
         }
-        for (PackageParser.Package p : others) {
+        for (AndroidPackage p : others) {
             // We assume here that there are no core apps left.
-            if (p.coreApp) {
+            if (p.isCoreApp()) {
                 throw new IllegalStateException("Found a core app that's not important");
             }
             mDexoptCommands.addAll(
@@ -150,8 +150,8 @@
         if (spaceAvailable < BULK_DELETE_THRESHOLD) {
             Log.i(TAG, "Low on space, deleting oat files in an attempt to free up space: "
                     + PackageManagerServiceUtils.packagesToString(others));
-            for (PackageParser.Package pkg : others) {
-                mPackageManagerService.deleteOatArtifactsOfPackage(pkg.packageName);
+            for (AndroidPackage pkg : others) {
+                mPackageManagerService.deleteOatArtifactsOfPackage(pkg.getPackageName());
             }
         }
         long spaceAvailableNow = getAvailableSpace();
@@ -161,15 +161,15 @@
         if (DEBUG_DEXOPT) {
             try {
                 // Output some data about the packages.
-                PackageParser.Package lastUsed = Collections.max(important,
+                AndroidPackage lastUsed = Collections.max(important,
                         (pkg1, pkg2) -> Long.compare(
                                 pkg1.getLatestForegroundPackageUseTimeInMills(),
                                 pkg2.getLatestForegroundPackageUseTimeInMills()));
                 Log.d(TAG, "A/B OTA: lastUsed time = "
                         + lastUsed.getLatestForegroundPackageUseTimeInMills());
                 Log.d(TAG, "A/B OTA: deprioritized packages:");
-                for (PackageParser.Package pkg : others) {
-                    Log.d(TAG, "  " + pkg.packageName + " - "
+                for (AndroidPackage pkg : others) {
+                    Log.d(TAG, "  " + pkg.getPackageName() + " - "
                             + pkg.getLatestForegroundPackageUseTimeInMills());
                 }
             } catch (Exception ignored) {
@@ -262,7 +262,7 @@
     /**
      * Generate all dexopt commands for the given package.
      */
-    private synchronized List<String> generatePackageDexopts(PackageParser.Package pkg,
+    private synchronized List<String> generatePackageDexopts(AndroidPackage pkg,
             int compilationReason) {
         // Intercept and collect dexopt requests
         final List<String> commands = new ArrayList<String>();
@@ -336,8 +336,9 @@
         optimizer.performDexOpt(pkg,
                 null /* ISAs */,
                 null /* CompilerStats.PackageStats */,
-                mPackageManagerService.getDexManager().getPackageUseInfoOrDefault(pkg.packageName),
-                new DexoptOptions(pkg.packageName, compilationReason,
+                mPackageManagerService.getDexManager().getPackageUseInfoOrDefault(
+                        pkg.getPackageName()),
+                new DexoptOptions(pkg.getPackageName(), compilationReason,
                         DexoptOptions.DEXOPT_BOOT_COMPLETE));
 
         return commands;
@@ -359,10 +360,10 @@
         }
 
         // Look into all packages.
-        Collection<PackageParser.Package> pkgs = mPackageManagerService.getPackages();
+        Collection<AndroidPackage> pkgs = mPackageManagerService.getPackages();
         int packagePaths = 0;
         int pathsSuccessful = 0;
-        for (PackageParser.Package pkg : pkgs) {
+        for (AndroidPackage pkg : pkgs) {
             if (pkg == null) {
                 continue;
             }
@@ -371,27 +372,28 @@
             if (!PackageDexOptimizer.canOptimizePackage(pkg)) {
                 continue;
             }
-            if (pkg.codePath == null) {
+            if (pkg.getCodePath() == null) {
                 Slog.w(TAG, "Package " + pkg + " can be optimized but has null codePath");
                 continue;
             }
 
             // If the path is in /system, /vendor, /product or /system_ext, ignore. It will
             // have been ota-dexopted into /data/ota and moved into the dalvik-cache already.
-            if (pkg.codePath.startsWith("/system")
-                    || pkg.codePath.startsWith("/vendor")
-                    || pkg.codePath.startsWith("/product")
-                    || pkg.codePath.startsWith("/system_ext")) {
+            if (pkg.getCodePath().startsWith("/system")
+                    || pkg.getCodePath().startsWith("/vendor")
+                    || pkg.getCodePath().startsWith("/product")
+                    || pkg.getCodePath().startsWith("/system_ext")) {
                 continue;
             }
 
-            final String[] instructionSets = getAppDexInstructionSets(pkg.applicationInfo);
+            final String[] instructionSets = getAppDexInstructionSets(pkg.getPrimaryCpuAbi(),
+                    pkg.getSecondaryCpuAbi());
             final List<String> paths = pkg.getAllCodePathsExcludingResourceOnly();
             final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
             for (String dexCodeInstructionSet : dexCodeInstructionSets) {
                 for (String path : paths) {
-                    String oatDir = PackageDexOptimizer.getOatDir(new File(pkg.codePath)).
-                            getAbsolutePath();
+                    String oatDir = PackageDexOptimizer.getOatDir(
+                            new File(pkg.getCodePath())).getAbsolutePath();
 
                     // TODO: Check first whether there is an artifact, to save the roundtrip time.
 
diff --git a/services/core/java/com/android/server/pm/PackageAbiHelper.java b/services/core/java/com/android/server/pm/PackageAbiHelper.java
index c21d0cf..d7c161c 100644
--- a/services/core/java/com/android/server/pm/PackageAbiHelper.java
+++ b/services/core/java/com/android/server/pm/PackageAbiHelper.java
@@ -17,7 +17,8 @@
 package com.android.server.pm;
 
 import android.annotation.Nullable;
-import android.content.pm.PackageParser;
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.ParsedPackage;
 import android.util.Pair;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -25,21 +26,21 @@
 import java.io.File;
 import java.util.Set;
 
+// TODO: Move to .parsing sub-package
 @VisibleForTesting
 public interface PackageAbiHelper {
     /**
      * Derive and get the location of native libraries for the given package,
      * which varies depending on where and how the package was installed.
      */
-    NativeLibraryPaths getNativeLibraryPaths(
-            PackageParser.Package pkg, File appLib32InstallDir);
+    NativeLibraryPaths getNativeLibraryPaths(AndroidPackage pkg, File appLib32InstallDir);
 
     /**
      * Calculate the abis for a bundled app. These can uniquely be determined from the contents of
      * the system partition, i.e whether it contains 64 or 32 bit shared libraries etc. We do not
      * validate any of this information, and instead assume that the system was built sensibly.
      */
-    Abis getBundledAppAbis(PackageParser.Package pkg);
+    Abis getBundledAppAbis(AndroidPackage pkg);
 
     /**
      * Derive the ABI of a non-system package located at {@code pkg}. This information
@@ -48,7 +49,7 @@
      * If {@code extractLibs} is true, native libraries are extracted from the app if required.
      */
     Pair<Abis, NativeLibraryPaths> derivePackageAbi(
-            PackageParser.Package pkg, String cpuAbiOverride, boolean extractLibs)
+            AndroidPackage pkg, String cpuAbiOverride, boolean extractLibs)
             throws PackageManagerException;
 
     /**
@@ -69,11 +70,11 @@
      */
     @Nullable
     String getAdjustedAbiForSharedUser(
-            Set<PackageSetting> packagesForUser, PackageParser.Package scannedPackage);
+            Set<PackageSetting> packagesForUser, AndroidPackage scannedPackage);
 
     /**
      * The native library paths and related properties that should be set on a
-     * {@link android.content.pm.PackageParser.Package}.
+     * {@link ParsedPackage}.
      */
     final class NativeLibraryPaths {
         public final String nativeLibraryRootDir;
@@ -91,11 +92,11 @@
             this.secondaryNativeLibraryDir = secondaryNativeLibraryDir;
         }
 
-        public void applyTo(PackageParser.Package pkg) {
-            pkg.applicationInfo.nativeLibraryRootDir = nativeLibraryRootDir;
-            pkg.applicationInfo.nativeLibraryRootRequiresIsa = nativeLibraryRootRequiresIsa;
-            pkg.applicationInfo.nativeLibraryDir = nativeLibraryDir;
-            pkg.applicationInfo.secondaryNativeLibraryDir = secondaryNativeLibraryDir;
+        public void applyTo(ParsedPackage pkg) {
+            pkg.setNativeLibraryRootDir(nativeLibraryRootDir)
+                    .setNativeLibraryRootRequiresIsa(nativeLibraryRootRequiresIsa)
+                    .setNativeLibraryDir(nativeLibraryDir)
+                    .setSecondaryNativeLibraryDir(secondaryNativeLibraryDir);
         }
     }
 
@@ -112,13 +113,13 @@
             this.secondary = secondary;
         }
 
-        Abis(PackageParser.Package pkg) {
-            this(pkg.applicationInfo.primaryCpuAbi, pkg.applicationInfo.secondaryCpuAbi);
+        Abis(AndroidPackage pkg) {
+            this(pkg.getPrimaryCpuAbi(), pkg.getSecondaryCpuAbi());
         }
 
-        public void applyTo(PackageParser.Package pkg) {
-            pkg.applicationInfo.primaryCpuAbi = primary;
-            pkg.applicationInfo.secondaryCpuAbi = secondary;
+        public void applyTo(ParsedPackage pkg) {
+            pkg.setPrimaryCpuAbi(primary)
+                    .setSecondaryCpuAbi(secondary);
         }
         public void applyTo(PackageSetting pkgSetting) {
             // pkgSetting might be null during rescan following uninstall of updates
diff --git a/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java b/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
index 7e47800..66acb86 100644
--- a/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
+++ b/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
@@ -29,7 +29,7 @@
 import android.annotation.Nullable;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
-import android.content.pm.PackageParser;
+import android.content.pm.parsing.AndroidPackage;
 import android.os.Build;
 import android.os.Environment;
 import android.os.FileUtils;
@@ -132,10 +132,10 @@
 
     @Override
     public NativeLibraryPaths getNativeLibraryPaths(
-            PackageParser.Package pkg, File appLib32InstallDir) {
-        return getNativeLibraryPaths(new Abis(pkg), appLib32InstallDir, pkg.codePath,
-                pkg.applicationInfo.sourceDir, pkg.applicationInfo.isSystemApp(),
-                pkg.applicationInfo.isUpdatedSystemApp());
+            AndroidPackage pkg, File appLib32InstallDir) {
+        return getNativeLibraryPaths(new Abis(pkg), appLib32InstallDir, pkg.getCodePath(),
+                pkg.getBaseCodePath(), pkg.isSystemApp(),
+                pkg.isUpdatedSystemApp());
     }
 
     private static NativeLibraryPaths getNativeLibraryPaths(final Abis abis,
@@ -202,12 +202,12 @@
     }
 
     @Override
-    public Abis getBundledAppAbis(PackageParser.Package pkg) {
-        final String apkName = deriveCodePathName(pkg.applicationInfo.getCodePath());
+    public Abis getBundledAppAbis(AndroidPackage pkg) {
+        final String apkName = deriveCodePathName(pkg.getCodePath());
 
         // If "/system/lib64/apkname" exists, assume that is the per-package
         // native library directory to use; otherwise use "/system/lib/apkname".
-        final String apkRoot = calculateBundledApkRoot(pkg.applicationInfo.sourceDir);
+        final String apkRoot = calculateBundledApkRoot(pkg.getBaseCodePath());
         final Abis abis = getBundledAppAbi(pkg, apkRoot, apkName);
         return abis;
     }
@@ -220,8 +220,8 @@
      *                {@code /oem} under which system libraries are installed.
      * @param apkName the name of the installed package.
      */
-    private Abis getBundledAppAbi(PackageParser.Package pkg, String apkRoot, String apkName) {
-        final File codeFile = new File(pkg.codePath);
+    private Abis getBundledAppAbi(AndroidPackage pkg, String apkRoot, String apkName) {
+        final File codeFile = new File(pkg.getCodePath());
 
         final boolean has64BitLibs;
         final boolean has32BitLibs;
@@ -273,7 +273,7 @@
             // ABI that's higher on the list, i.e, a device that's configured to prefer
             // 64 bit apps will see a 64 bit primary ABI,
 
-            if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_MULTIARCH) == 0) {
+            if ((pkg.getFlags() & ApplicationInfo.FLAG_MULTIARCH) == 0) {
                 Slog.e(PackageManagerService.TAG,
                         "Package " + pkg + " has multiple bundled libs, but is not multiarch.");
             }
@@ -294,14 +294,14 @@
 
     @Override
     public Pair<Abis, NativeLibraryPaths> derivePackageAbi(
-            PackageParser.Package pkg, String cpuAbiOverride, boolean extractLibs)
+            AndroidPackage pkg, String cpuAbiOverride, boolean extractLibs)
             throws PackageManagerException {
         // Give ourselves some initial paths; we'll come back for another
         // pass once we've determined ABI below.
         final NativeLibraryPaths initialLibraryPaths = getNativeLibraryPaths(new Abis(pkg),
-                PackageManagerService.sAppLib32InstallDir, pkg.codePath,
-                pkg.applicationInfo.sourceDir, pkg.applicationInfo.isSystemApp(),
-                pkg.applicationInfo.isUpdatedSystemApp());
+                PackageManagerService.sAppLib32InstallDir, pkg.getCodePath(),
+                pkg.getBaseCodePath(), pkg.isSystemApp(),
+                pkg.isUpdatedSystemApp());
 
         // We shouldn't attempt to extract libs from system app when it was not updated.
         if (PackageManagerService.isSystemApp(pkg) && !pkg.isUpdatedSystemApp()) {
@@ -329,12 +329,13 @@
             // Null out the abis so that they can be recalculated.
             primaryCpuAbi = null;
             secondaryCpuAbi = null;
-            if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_MULTIARCH) != 0) {
+            if ((pkg.getFlags() & ApplicationInfo.FLAG_MULTIARCH) != 0) {
                 // Warn if we've set an abiOverride for multi-lib packages..
                 // By definition, we need to copy both 32 and 64 bit libraries for
                 // such packages.
-                if (pkg.cpuAbiOverride != null
-                        && !NativeLibraryHelper.CLEAR_ABI_OVERRIDE.equals(pkg.cpuAbiOverride)) {
+                if (pkg.getCpuAbiOverride() != null
+                        && !NativeLibraryHelper.CLEAR_ABI_OVERRIDE.equals(
+                        pkg.getCpuAbiOverride())) {
                     Slog.w(PackageManagerService.TAG,
                             "Ignoring abiOverride for multi arch application.");
                 }
@@ -409,7 +410,7 @@
                 if (abi32 >= 0) {
                     final String abi = Build.SUPPORTED_32_BIT_ABIS[abi32];
                     if (abi64 >= 0) {
-                        if (pkg.use32bitAbi) {
+                        if (pkg.isUse32BitAbi()) {
                             secondaryCpuAbi = primaryCpuAbi;
                             primaryCpuAbi = abi;
                         } else {
@@ -482,9 +483,9 @@
         final Abis abis = new Abis(primaryCpuAbi, secondaryCpuAbi);
         return new Pair<>(abis,
                 getNativeLibraryPaths(abis, PackageManagerService.sAppLib32InstallDir,
-                        pkg.codePath, pkg.applicationInfo.sourceDir,
-                        pkg.applicationInfo.isSystemApp(),
-                        pkg.applicationInfo.isUpdatedSystemApp()));
+                        pkg.getCodePath(), pkg.getBaseCodePath(),
+                        pkg.isSystemApp(),
+                        pkg.isUpdatedSystemApp()));
     }
 
     /**
@@ -503,11 +504,11 @@
     @Override
     @Nullable
     public String getAdjustedAbiForSharedUser(
-            Set<PackageSetting> packagesForUser, PackageParser.Package scannedPackage) {
+            Set<PackageSetting> packagesForUser, AndroidPackage scannedPackage) {
         String requiredInstructionSet = null;
-        if (scannedPackage != null && scannedPackage.applicationInfo.primaryCpuAbi != null) {
+        if (scannedPackage != null && scannedPackage.getPrimaryCpuAbi() != null) {
             requiredInstructionSet = VMRuntime.getInstructionSet(
-                    scannedPackage.applicationInfo.primaryCpuAbi);
+                    scannedPackage.getPrimaryCpuAbi());
         }
 
         PackageSetting requirer = null;
@@ -516,7 +517,7 @@
             // when scannedPackage is an update of an existing package. Without this check,
             // we will never be able to change the ABI of any package belonging to a shared
             // user, even if it's compatible with other packages.
-            if (scannedPackage != null && scannedPackage.packageName.equals(ps.name)) {
+            if (scannedPackage != null && scannedPackage.getPackageName().equals(ps.name)) {
                 continue;
             }
             if (ps.primaryCpuAbiString == null) {
@@ -554,7 +555,7 @@
         } else {
             // requirer == null implies that we're updating all ABIs in the set to
             // match scannedPackage.
-            adjustedAbi = scannedPackage.applicationInfo.primaryCpuAbi;
+            adjustedAbi = scannedPackage.getPrimaryCpuAbi();
         }
         return adjustedAbi;
     }
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 4f7c8c8..2b42221 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -41,10 +41,10 @@
 import android.annotation.Nullable;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageParser;
 import android.content.pm.SharedLibraryInfo;
 import android.content.pm.dex.ArtManager;
 import android.content.pm.dex.DexMetadataHelper;
+import android.content.pm.parsing.AndroidPackage;
 import android.os.FileUtils;
 import android.os.PowerManager;
 import android.os.SystemClock;
@@ -53,6 +53,7 @@
 import android.os.WorkSource;
 import android.util.Log;
 import android.util.Slog;
+import android.util.SparseArray;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.IndentingPrintWriter;
@@ -109,9 +110,9 @@
         this.mSystemReady = from.mSystemReady;
     }
 
-    static boolean canOptimizePackage(PackageParser.Package pkg) {
+    static boolean canOptimizePackage(AndroidPackage pkg) {
         // We do not dexopt a package with no code.
-        if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) == 0) {
+        if ((pkg.getFlags() & ApplicationInfo.FLAG_HAS_CODE) == 0) {
             return false;
         }
 
@@ -125,18 +126,18 @@
      * <p>Calls to {@link com.android.server.pm.Installer#dexopt} on {@link #mInstaller} are
      * synchronized on {@link #mInstallLock}.
      */
-    int performDexOpt(PackageParser.Package pkg,
+    int performDexOpt(AndroidPackage pkg,
             String[] instructionSets, CompilerStats.PackageStats packageStats,
             PackageDexUsage.PackageUseInfo packageUseInfo, DexoptOptions options) {
-        if (pkg.applicationInfo.uid == -1) {
-            throw new IllegalArgumentException("Dexopt for " + pkg.packageName
+        if (pkg.getUid() == -1) {
+            throw new IllegalArgumentException("Dexopt for " + pkg.getPackageName()
                     + " has invalid uid.");
         }
         if (!canOptimizePackage(pkg)) {
             return DEX_OPT_SKIPPED;
         }
         synchronized (mInstallLock) {
-            final long acquireTime = acquireWakeLockLI(pkg.applicationInfo.uid);
+            final long acquireTime = acquireWakeLockLI(pkg.getUid());
             try {
                 return performDexOptLI(pkg, instructionSets,
                         packageStats, packageUseInfo, options);
@@ -151,19 +152,20 @@
      * It assumes the install lock is held.
      */
     @GuardedBy("mInstallLock")
-    private int performDexOptLI(PackageParser.Package pkg,
+    private int performDexOptLI(AndroidPackage pkg,
             String[] targetInstructionSets, CompilerStats.PackageStats packageStats,
             PackageDexUsage.PackageUseInfo packageUseInfo, DexoptOptions options) {
-        final List<SharedLibraryInfo> sharedLibraries = pkg.usesLibraryInfos;
+        final List<SharedLibraryInfo> sharedLibraries = pkg.getUsesLibraryInfos();
         final String[] instructionSets = targetInstructionSets != null ?
-                targetInstructionSets : getAppDexInstructionSets(pkg.applicationInfo);
+                targetInstructionSets : getAppDexInstructionSets(pkg.getPrimaryCpuAbi(),
+                pkg.getSecondaryCpuAbi());
         final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
         final List<String> paths = pkg.getAllCodePaths();
 
-        int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
+        int sharedGid = UserHandle.getSharedAppGid(pkg.getUid());
         if (sharedGid == -1) {
-            Slog.wtf(TAG, "Well this is awkward; package " + pkg.applicationInfo.name + " had UID "
-                    + pkg.applicationInfo.uid, new Throwable());
+            Slog.wtf(TAG, "Well this is awkward; package " + pkg.getAppInfoName() + " had UID "
+                    + pkg.getUid(), new Throwable());
             sharedGid = android.os.Process.NOBODY_UID;
         }
 
@@ -171,21 +173,21 @@
         // For each code path in the package, this array contains the class loader context that
         // needs to be passed to dexopt in order to ensure correct optimizations.
         boolean[] pathsWithCode = new boolean[paths.size()];
-        pathsWithCode[0] = (pkg.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0;
+        pathsWithCode[0] = (pkg.getFlags() & ApplicationInfo.FLAG_HAS_CODE) != 0;
         for (int i = 1; i < paths.size(); i++) {
-            pathsWithCode[i] = (pkg.splitFlags[i - 1] & ApplicationInfo.FLAG_HAS_CODE) != 0;
+            pathsWithCode[i] = (pkg.getSplitFlags()[i - 1] & ApplicationInfo.FLAG_HAS_CODE) != 0;
         }
         String[] classLoaderContexts = DexoptUtils.getClassLoaderContexts(
-                pkg.applicationInfo, sharedLibraries, pathsWithCode);
+                pkg, sharedLibraries, pathsWithCode);
 
         // Sanity check that we do not call dexopt with inconsistent data.
         if (paths.size() != classLoaderContexts.length) {
-            String[] splitCodePaths = pkg.applicationInfo.getSplitCodePaths();
+            String[] splitCodePaths = pkg.getSplitCodePaths();
             throw new IllegalStateException("Inconsistent information "
                 + "between PackageParser.Package and its ApplicationInfo. "
                 + "pkg.getAllCodePaths=" + paths
-                + " pkg.applicationInfo.getBaseCodePath=" + pkg.applicationInfo.getBaseCodePath()
-                + " pkg.applicationInfo.getSplitCodePaths="
+                + " pkg.getBaseCodePath=" + pkg.getBaseCodePath()
+                + " pkg.getSplitCodePaths="
                 + (splitCodePaths == null ? "null" : Arrays.toString(splitCodePaths)));
         }
 
@@ -211,7 +213,8 @@
                 }
             }
 
-            String profileName = ArtManager.getProfileName(i == 0 ? null : pkg.splitNames[i - 1]);
+            String profileName = ArtManager.getProfileName(
+                    i == 0 ? null : pkg.getSplitNames()[i - 1]);
 
             String dexMetadataPath = null;
             if (options.isDexoptInstallWithDexMetadata()) {
@@ -222,7 +225,7 @@
 
             final boolean isUsedByOtherApps = options.isDexoptAsSharedLibrary()
                     || packageUseInfo.isUsedByOtherApps(path);
-            final String compilerFilter = getRealCompilerFilter(pkg.applicationInfo,
+            final String compilerFilter = getRealCompilerFilter(pkg,
                 options.getCompilerFilter(), isUsedByOtherApps);
             final boolean profileUpdated = options.isCheckForProfileUpdates() &&
                 isProfileUpdated(pkg, sharedGid, profileName, compilerFilter);
@@ -257,7 +260,7 @@
      *      DEX_OPT_SKIPPED if the path does not need to be deopt-ed.
      */
     @GuardedBy("mInstallLock")
-    private int dexOptPath(PackageParser.Package pkg, String path, String isa,
+    private int dexOptPath(AndroidPackage pkg, String path, String isa,
             String compilerFilter, boolean profileUpdated, String classLoaderContext,
             int dexoptFlags, int uid, CompilerStats.PackageStats packageStats, boolean downgrade,
             String profileName, String dexMetadataPath, int compilationReason) {
@@ -270,7 +273,7 @@
         String oatDir = getPackageOatDirIfSupported(pkg);
 
         Log.i(TAG, "Running dexopt (dexoptNeeded=" + dexoptNeeded + ") on: " + path
-                + " pkg=" + pkg.applicationInfo.packageName + " isa=" + isa
+                + " pkg=" + pkg.getAppInfoPackageName() + " isa=" + isa
                 + " dexoptFlags=" + printDexoptFlags(dexoptFlags)
                 + " targetFilter=" + compilerFilter + " oatDir=" + oatDir
                 + " classLoaderContext=" + classLoaderContext);
@@ -281,9 +284,9 @@
             // TODO: Consider adding 2 different APIs for primary and secondary dexopt.
             // installd only uses downgrade flag for secondary dex files and ignores it for
             // primary dex files.
-            mInstaller.dexopt(path, uid, pkg.packageName, isa, dexoptNeeded, oatDir, dexoptFlags,
-                    compilerFilter, pkg.volumeUuid, classLoaderContext, pkg.applicationInfo.seInfo,
-                    false /* downgrade*/, pkg.applicationInfo.targetSdkVersion,
+            mInstaller.dexopt(path, uid, pkg.getPackageName(), isa, dexoptNeeded, oatDir,
+                    dexoptFlags, compilerFilter, pkg.getVolumeUuid(), classLoaderContext,
+                    pkg.getSeInfo(), false /* downgrade*/, pkg.getTargetSdkVersion(),
                     profileName, dexMetadataPath,
                     getAugmentedReasonName(compilationReason, dexMetadataPath != null));
 
@@ -446,9 +449,10 @@
     /**
      * Dumps the dexopt state of the given package {@code pkg} to the given {@code PrintWriter}.
      */
-    void dumpDexoptState(IndentingPrintWriter pw, PackageParser.Package pkg,
+    void dumpDexoptState(IndentingPrintWriter pw, AndroidPackage pkg,
             PackageDexUsage.PackageUseInfo useInfo) {
-        final String[] instructionSets = getAppDexInstructionSets(pkg.applicationInfo);
+        final String[] instructionSets = getAppDexInstructionSets(pkg.getPrimaryCpuAbi(),
+                pkg.getSecondaryCpuAbi());
         final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
 
         final List<String> paths = pkg.getAllCodePathsExcludingResourceOnly();
@@ -504,7 +508,7 @@
         // When an app or priv app is configured to run out of box, only verify it.
         if (info.isEmbeddedDexUsed()
                 || (info.isPrivilegedApp()
-                    && DexManager.isPackageSelectedToRunOob(info.packageName))) {
+                && DexManager.isPackageSelectedToRunOob(info.packageName))) {
             return "verify";
         }
 
@@ -535,12 +539,43 @@
     }
 
     /**
-     * Computes the dex flags that needs to be pass to installd for the given package and compiler
-     * filter.
+     * Returns the compiler filter that should be used to optimize the package code.
+     * The target filter will be updated if the package code is used by other apps
+     * or if it has the safe mode flag set.
      */
-    private int getDexFlags(PackageParser.Package pkg, String compilerFilter,
-            DexoptOptions options) {
-        return getDexFlags(pkg.applicationInfo, compilerFilter, options);
+    private String getRealCompilerFilter(AndroidPackage pkg, String targetCompilerFilter,
+            boolean isUsedByOtherApps) {
+        // When an app or priv app is configured to run out of box, only verify it.
+        if (pkg.isEmbeddedDexUsed()
+                || (pkg.isPrivileged()
+                    && DexManager.isPackageSelectedToRunOob(pkg.getPackageName()))) {
+            return "verify";
+        }
+
+        // We force vmSafeMode on debuggable apps as well:
+        //  - the runtime ignores their compiled code
+        //  - they generally have lots of methods that could make the compiler used run
+        //    out of memory (b/130828957)
+        // Note that forcing the compiler filter here applies to all compilations (even if they
+        // are done via adb shell commands). That's ok because right now the runtime will ignore
+        // the compiled code anyway. The alternative would have been to update either
+        // PackageDexOptimizer#canOptimizePackage or PackageManagerService#getOptimizablePackages
+        // but that would have the downside of possibly producing a big odex files which would
+        // be ignored anyway.
+        boolean vmSafeModeOrDebuggable = ((pkg.getFlags() & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0)
+                || ((pkg.getFlags() & ApplicationInfo.FLAG_DEBUGGABLE) != 0);
+
+        if (vmSafeModeOrDebuggable) {
+            return getSafeModeCompilerFilter(targetCompilerFilter);
+        }
+
+        if (isProfileGuidedCompilerFilter(targetCompilerFilter) && isUsedByOtherApps) {
+            // If the dex files is used by other apps, apply the shared filter.
+            return PackageManagerServiceCompilerMapping.getCompilerFilterForReason(
+                    PackageManagerService.REASON_SHARED);
+        }
+
+        return targetCompilerFilter;
     }
 
     private boolean isAppImageEnabled() {
@@ -548,7 +583,24 @@
     }
 
     private int getDexFlags(ApplicationInfo info, String compilerFilter, DexoptOptions options) {
-        int flags = info.flags;
+        return getDexFlags(info.flags, info.getHiddenApiEnforcementPolicy(),
+                info.splitDependencies, info.requestsIsolatedSplitLoading(), compilerFilter,
+                options);
+    }
+    private int getDexFlags(AndroidPackage pkg, String compilerFilter,
+            DexoptOptions options) {
+        return getDexFlags(pkg.getFlags(), pkg.getHiddenApiEnforcementPolicy(),
+                pkg.getSplitDependencies(), pkg.requestsIsolatedSplitLoading(), compilerFilter,
+                options);
+    }
+
+    /**
+     * Computes the dex flags that needs to be pass to installd for the given package and compiler
+     * filter.
+     */
+    private int getDexFlags(int flags, int hiddenApiEnforcementPolicy,
+            SparseArray<int[]> splitDependencies, boolean requestsIsolatedSplitLoading,
+            String compilerFilter, DexoptOptions options) {
         boolean debuggable = (flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
         // Profile guide compiled oat files should not be public unles they are based
         // on profiles from dex metadata archives.
@@ -560,7 +612,9 @@
         // Some apps are executed with restrictions on hidden API usage. If this app is one
         // of them, pass a flag to dexopt to enable the same restrictions during compilation.
         // TODO we should pass the actual flag value to dexopt, rather than assuming blacklist
-        int hiddenApiFlag = info.getHiddenApiEnforcementPolicy() == HIDDEN_API_ENFORCEMENT_DISABLED
+        // TODO(b/135203078): This flag is no longer set as part of AndroidPackage
+        //  and may not be preserved
+        int hiddenApiFlag = hiddenApiEnforcementPolicy == HIDDEN_API_ENFORCEMENT_DISABLED
                 ? 0
                 : DEXOPT_ENABLE_HIDDEN_API_CHECKS;
         // Avoid generating CompactDex for modes that are latency critical.
@@ -578,8 +632,8 @@
         // declare inter-split dependencies, then all the splits will be loaded in the base
         // apk class loader (in the order of their definition, otherwise disable app images
         // because they are unsupported for multiple class loaders. b/7269679
-        boolean generateAppImage = isProfileGuidedFilter && (info.splitDependencies == null ||
-                !info.requestsIsolatedSplitLoading()) && isAppImageEnabled();
+        boolean generateAppImage = isProfileGuidedFilter && (splitDependencies == null ||
+                !requestsIsolatedSplitLoading) && isAppImageEnabled();
         int dexFlags =
                 (isPublic ? DEXOPT_PUBLIC : 0)
                 | (debuggable ? DEXOPT_DEBUGGABLE : 0)
@@ -617,7 +671,7 @@
      * current profile and the reference profile will be merged and subsequent calls
      * may return a different result.
      */
-    private boolean isProfileUpdated(PackageParser.Package pkg, int uid, String profileName,
+    private boolean isProfileUpdated(AndroidPackage pkg, int uid, String profileName,
             String compilerFilter) {
         // Check if we are allowed to merge and if the compiler filter is profile guided.
         if (!isProfileGuidedCompilerFilter(compilerFilter)) {
@@ -625,7 +679,7 @@
         }
         // Merge profiles. It returns whether or not there was an updated in the profile info.
         try {
-            return mInstaller.mergeProfiles(uid, pkg.packageName, profileName);
+            return mInstaller.mergeProfiles(uid, pkg.getPackageName(), profileName);
         } catch (InstallerException e) {
             Slog.w(TAG, "Failed to merge profiles", e);
         }
@@ -645,11 +699,11 @@
      * not needed or unsupported for the package.
      */
     @Nullable
-    private String getPackageOatDirIfSupported(PackageParser.Package pkg) {
+    private String getPackageOatDirIfSupported(AndroidPackage pkg) {
         if (!pkg.canHaveOatDir()) {
             return null;
         }
-        File codePath = new File(pkg.codePath);
+        File codePath = new File(pkg.getCodePath());
         if (!codePath.isDirectory()) {
             return null;
         }
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 883baf7..518ec50 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -66,6 +66,7 @@
 import android.content.pm.PackageParser.PackageLite;
 import android.content.pm.PackageParser.PackageParserException;
 import android.content.pm.dex.DexMetadataHelper;
+import android.content.pm.parsing.ApkLiteParseUtils;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.os.Binder;
@@ -1677,7 +1678,7 @@
         for (File addedFile : addedFiles) {
             final ApkLite apk;
             try {
-                apk = PackageParser.parseApkLite(
+                apk = ApkLiteParseUtils.parseApkLite(
                         addedFile, PackageParser.PARSE_COLLECT_CERTIFICATES);
             } catch (PackageParserException e) {
                 throw PackageManagerException.from(e);
@@ -1776,7 +1777,7 @@
             ApplicationInfo appInfo = pkgInfo.applicationInfo;
             try {
                 existing = PackageParser.parsePackageLite(new File(appInfo.getCodePath()), 0);
-                existingBase = PackageParser.parseApkLite(new File(appInfo.getBaseCodePath()),
+                existingBase = ApkLiteParseUtils.parseApkLite(new File(appInfo.getBaseCodePath()),
                         PackageParser.PARSE_COLLECT_CERTIFICATES);
             } catch (PackageParserException e) {
                 throw PackageManagerException.from(e);
diff --git a/services/core/java/com/android/server/pm/PackageKeySetData.java b/services/core/java/com/android/server/pm/PackageKeySetData.java
index 031b5ce..10685b0 100644
--- a/services/core/java/com/android/server/pm/PackageKeySetData.java
+++ b/services/core/java/com/android/server/pm/PackageKeySetData.java
@@ -20,6 +20,8 @@
 
 import com.android.internal.util.ArrayUtils;
 
+import java.util.Map;
+
 public class PackageKeySetData {
 
     static final long KEYSET_UNASSIGNED = -1;
@@ -90,16 +92,13 @@
     /*
      * Replace defined keysets with new ones.
      */
-    protected void setAliases(ArrayMap<String, Long> newAliases) {
+    protected void setAliases(Map<String, Long> newAliases) {
 
         /* remove old aliases */
         removeAllDefinedKeySets();
 
         /* add new ones */
-        final int newAliasSize = newAliases.size();
-        for (int i = 0; i < newAliasSize; i++) {
-            mKeySetAliases.put(newAliases.keyAt(i), newAliases.valueAt(i));;
-        }
+        mKeySetAliases.putAll(newAliases);
     }
 
     protected void addDefinedKeySet(long ks, String alias) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 3d4247e7..8fef6b9 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -34,7 +34,6 @@
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
-import static android.content.pm.PackageManager.DELETE_KEEP_DATA;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_POLICY_FIXED;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKED_COMPAT;
@@ -160,7 +159,6 @@
 import android.content.pm.IntentFilterVerificationInfo;
 import android.content.pm.KeySet;
 import android.content.pm.ModuleInfo;
-import android.content.pm.PackageBackwardCompatibility;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageInfoLite;
 import android.content.pm.PackageInstaller;
@@ -170,7 +168,6 @@
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.PackageManagerInternal.PackageListObserver;
 import android.content.pm.PackageParser;
-import android.content.pm.PackageParser.ActivityIntentInfo;
 import android.content.pm.PackageParser.PackageLite;
 import android.content.pm.PackageParser.PackageParserException;
 import android.content.pm.PackageParser.ParseFlags;
@@ -195,6 +192,19 @@
 import android.content.pm.dex.ArtManager;
 import android.content.pm.dex.DexMetadataHelper;
 import android.content.pm.dex.IArtManager;
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.ApkParseUtils;
+import android.content.pm.parsing.ComponentParseUtils.ParsedActivity;
+import android.content.pm.parsing.ComponentParseUtils.ParsedActivityIntentInfo;
+import android.content.pm.parsing.ComponentParseUtils.ParsedComponent;
+import android.content.pm.parsing.ComponentParseUtils.ParsedInstrumentation;
+import android.content.pm.parsing.ComponentParseUtils.ParsedPermission;
+import android.content.pm.parsing.ComponentParseUtils.ParsedProvider;
+import android.content.pm.parsing.ComponentParseUtils.ParsedService;
+import android.content.pm.parsing.PackageImpl;
+import android.content.pm.parsing.PackageInfoUtils;
+import android.content.pm.parsing.ParsedPackage;
+import android.content.pm.parsing.library.PackageBackwardCompatibility;
 import android.content.res.Resources;
 import android.content.rollback.IRollbackManager;
 import android.database.ContentObserver;
@@ -462,20 +472,19 @@
     static final int SCAN_REQUIRE_KNOWN = 1 << 7;
     static final int SCAN_MOVE = 1 << 8;
     static final int SCAN_INITIAL = 1 << 9;
-    static final int SCAN_CHECK_ONLY = 1 << 10;
-    static final int SCAN_DONT_KILL_APP = 1 << 11;
-    static final int SCAN_IGNORE_FROZEN = 1 << 12;
-    static final int SCAN_FIRST_BOOT_OR_UPGRADE = 1 << 13;
-    static final int SCAN_AS_INSTANT_APP = 1 << 14;
-    static final int SCAN_AS_FULL_APP = 1 << 15;
-    static final int SCAN_AS_VIRTUAL_PRELOAD = 1 << 16;
-    static final int SCAN_AS_SYSTEM = 1 << 17;
-    static final int SCAN_AS_PRIVILEGED = 1 << 18;
-    static final int SCAN_AS_OEM = 1 << 19;
-    static final int SCAN_AS_VENDOR = 1 << 20;
-    static final int SCAN_AS_PRODUCT = 1 << 21;
-    static final int SCAN_AS_SYSTEM_EXT = 1 << 22;
-    static final int SCAN_AS_ODM = 1 << 23;
+    static final int SCAN_DONT_KILL_APP = 1 << 10;
+    static final int SCAN_IGNORE_FROZEN = 1 << 11;
+    static final int SCAN_FIRST_BOOT_OR_UPGRADE = 1 << 12;
+    static final int SCAN_AS_INSTANT_APP = 1 << 13;
+    static final int SCAN_AS_FULL_APP = 1 << 14;
+    static final int SCAN_AS_VIRTUAL_PRELOAD = 1 << 15;
+    static final int SCAN_AS_SYSTEM = 1 << 16;
+    static final int SCAN_AS_PRIVILEGED = 1 << 17;
+    static final int SCAN_AS_OEM = 1 << 18;
+    static final int SCAN_AS_VENDOR = 1 << 19;
+    static final int SCAN_AS_PRODUCT = 1 << 20;
+    static final int SCAN_AS_SYSTEM_EXT = 1 << 21;
+    static final int SCAN_AS_ODM = 1 << 22;
 
     @IntDef(flag = true, prefix = { "SCAN_" }, value = {
             SCAN_NO_DEX,
@@ -486,7 +495,6 @@
             SCAN_REQUIRE_KNOWN,
             SCAN_MOVE,
             SCAN_INITIAL,
-            SCAN_CHECK_ONLY,
             SCAN_DONT_KILL_APP,
             SCAN_IGNORE_FROZEN,
             SCAN_FIRST_BOOT_OR_UPGRADE,
@@ -605,11 +613,19 @@
     public static final int REASON_LAST = REASON_SHARED;
 
     /**
-     * Whether the package parser cache is enabled.
+     * The initial enabled state of the cache before other checks are done.
      */
     private static final boolean DEFAULT_PACKAGE_PARSER_CACHE_ENABLED = true;
 
     /**
+     * Whether to skip all other checks and force the cache to be enabled.
+     *
+     * Setting this to true will cause the cache to be named "debug" to avoid eviction from
+     * build fingerprint changes.
+     */
+    private static final boolean FORCE_PACKAGE_PARSED_CACHE_ENABLED = false;
+
+    /**
      * Permissions required in order to receive instant application lifecycle broadcasts.
      */
     private static final String[] INSTANT_APP_BROADCAST_PERMISSION =
@@ -666,7 +682,7 @@
 
     // Keys are String (package name), values are Package.
     @GuardedBy("mLock")
-    final ArrayMap<String, PackageParser.Package> mPackages = new ArrayMap<>();
+    final ArrayMap<String, AndroidPackage> mPackages = new ArrayMap<>();
 
     // Keys are isolated uids and values are the uid of the application
     // that created the isolated proccess.
@@ -990,7 +1006,7 @@
             new ArrayMap<>();
 
     // Mapping from instrumentation class names to info about them.
-    final ArrayMap<ComponentName, PackageParser.Instrumentation> mInstrumentation =
+    final ArrayMap<ComponentName, ParsedInstrumentation> mInstrumentation =
             new ArrayMap<>();
 
     // Packages whose data we have transfered into another package, thus
@@ -1039,13 +1055,13 @@
     final ActivityInfo mResolveActivity = new ActivityInfo();
     final ResolveInfo mResolveInfo = new ResolveInfo();
     ComponentName mResolveComponentName;
-    PackageParser.Package mPlatformPackage;
+    AndroidPackage mPlatformPackage;
     ComponentName mCustomResolverComponentName;
 
     boolean mResolverReplaced = false;
 
     private final @Nullable ComponentName mIntentFilterVerifierComponent;
-    private final @Nullable IntentFilterVerifier<ActivityIntentInfo> mIntentFilterVerifier;
+    private final @Nullable IntentFilterVerifier<ParsedActivityIntentInfo> mIntentFilterVerifier;
 
     private int mIntentFilterVerificationToken = 0;
 
@@ -1080,14 +1096,19 @@
     private final IncrementalManager mIncrementalManager;
 
     private static class IFVerificationParams {
-        PackageParser.Package pkg;
+        String packageName;
+        boolean hasDomainUrls;
+        List<ParsedActivity> activities;
         boolean replacing;
         int userId;
         int verifierUid;
 
-        public IFVerificationParams(PackageParser.Package _pkg, boolean _replacing,
+        public IFVerificationParams(String packageName, boolean hasDomainUrls,
+                List<ParsedActivity> activities, boolean _replacing,
                 int _userId, int _verifierUid) {
-            pkg = _pkg;
+            this.packageName = packageName;
+            this.hasDomainUrls = hasDomainUrls;
+            this.activities = activities;
             replacing = _replacing;
             userId = _userId;
             verifierUid = _verifierUid;
@@ -1101,7 +1122,7 @@
         void receiveVerificationResponse(int verificationId);
     }
 
-    private class IntentVerifierProxy implements IntentFilterVerifier<ActivityIntentInfo> {
+    private class IntentVerifierProxy implements IntentFilterVerifier<ParsedActivityIntentInfo> {
         private Context mContext;
         private ComponentName mIntentFilterVerifierComponent;
         private ArrayList<Integer> mCurrentIntentFilterVerifications = new ArrayList<>();
@@ -1126,11 +1147,11 @@
 
                 String packageName = ivs.getPackageName();
 
-                ArrayList<PackageParser.ActivityIntentInfo> filters = ivs.getFilters();
+                ArrayList<ParsedActivityIntentInfo> filters = ivs.getFilters();
                 final int filterCount = filters.size();
                 ArraySet<String> domainsSet = new ArraySet<>();
                 for (int m=0; m<filterCount; m++) {
-                    PackageParser.ActivityIntentInfo filter = filters.get(m);
+                    ParsedActivityIntentInfo filter = filters.get(m);
                     domainsSet.addAll(filter.getHostsList());
                 }
                 synchronized (mLock) {
@@ -1182,14 +1203,14 @@
 
             final boolean verified = ivs.isVerified();
 
-            ArrayList<PackageParser.ActivityIntentInfo> filters = ivs.getFilters();
+            ArrayList<ParsedActivityIntentInfo> filters = ivs.getFilters();
             final int count = filters.size();
             if (DEBUG_DOMAIN_VERIFICATION) {
                 Slog.i(TAG, "Received verification response " + verificationId
                         + " for " + count + " filters, verified=" + verified);
             }
             for (int n=0; n<count; n++) {
-                PackageParser.ActivityIntentInfo filter = filters.get(n);
+                ParsedActivityIntentInfo filter = filters.get(n);
                 filter.setVerified(verified);
 
                 if (DEBUG_DOMAIN_VERIFICATION) Slog.d(TAG, "IntentFilter " + filter.toString()
@@ -1302,7 +1323,7 @@
 
         @Override
         public boolean addOneIntentFilterVerification(int verifierUid, int userId, int verificationId,
-                    ActivityIntentInfo filter, String packageName) {
+                ParsedActivityIntentInfo filter, String packageName) {
             if (!hasValidDomains(filter)) {
                 return false;
             }
@@ -1331,7 +1352,7 @@
         }
     }
 
-    private static boolean hasValidDomains(ActivityIntentInfo filter) {
+    private static boolean hasValidDomains(ParsedActivityIntentInfo filter) {
         return filter.hasCategory(Intent.CATEGORY_BROWSABLE)
                 && (filter.hasDataScheme(IntentFilter.SCHEME_HTTP) ||
                         filter.hasDataScheme(IntentFilter.SCHEME_HTTPS));
@@ -1598,7 +1619,7 @@
                         final List<String> whitelistedRestrictedPermissions = ((args.installFlags
                                 & PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS) != 0
                                     && parentRes.pkg != null)
-                                ? parentRes.pkg.requestedPermissions
+                                ? parentRes.pkg.getRequestedPermissions()
                                 : args.whitelistedRestrictedPermissions;
 
                         // Handle the parent package
@@ -1744,8 +1765,8 @@
                 }
                 case START_INTENT_FILTER_VERIFICATIONS: {
                     IFVerificationParams params = (IFVerificationParams) msg.obj;
-                    verifyIntentFiltersIfNeeded(params.userId, params.verifierUid,
-                            params.replacing, params.pkg);
+                    verifyIntentFiltersIfNeeded(params.userId, params.verifierUid, params.replacing,
+                            params.packageName, params.hasDomainUrls, params.activities);
                     break;
                 }
                 case INTENT_FILTER_VERIFIED: {
@@ -1895,20 +1916,11 @@
                                     ? res.removedInfo.installerPackageName
                                     : null;
 
-            // If this is the first time we have child packages for a disabled privileged
-            // app that had no children, we grant requested runtime permissions to the new
-            // children if the parent on the system image had them already granted.
-            if (res.pkg.parentPackage != null) {
-                final int callingUid = Binder.getCallingUid();
-                mPermissionManager.grantRuntimePermissionsGrantedToDisabledPackage(
-                        res.pkg, callingUid);
-            }
-
             synchronized (mLock) {
                 mInstantAppRegistry.onPackageInstalledLPw(res.pkg, res.newUsers);
             }
 
-            final String packageName = res.pkg.applicationInfo.packageName;
+            final String packageName = res.pkg.getAppInfoPackageName();
 
             // Determine the set of users who are adding this package for
             // the first time vs. those who are seeing an update.
@@ -1917,7 +1929,7 @@
             int[] updateUserIds = EMPTY_INT_ARRAY;
             int[] instantUserIds = EMPTY_INT_ARRAY;
             final boolean allNewUsers = res.origUsers == null || res.origUsers.length == 0;
-            final PackageSetting ps = (PackageSetting) res.pkg.mExtras;
+            final PackageSetting ps = getPackageSetting(res.pkg.getPackageName());
             for (int newUser : res.newUsers) {
                 final boolean isInstantApp = ps.getInstantApp(newUser);
                 if (allNewUsers) {
@@ -1951,13 +1963,14 @@
             }
 
             // Send installed broadcasts if the package is not a static shared lib.
-            if (res.pkg.staticSharedLibName == null) {
-                mProcessLoggingHandler.invalidateProcessLoggingBaseApkHash(res.pkg.baseCodePath);
+            if (res.pkg.getStaticSharedLibName() == null) {
+                mProcessLoggingHandler.invalidateProcessLoggingBaseApkHash(
+                        res.pkg.getBaseCodePath());
 
                 // Send added for users that see the package for the first time
                 // sendPackageAddedForNewUsers also deals with system apps
                 int appId = UserHandle.getAppId(res.uid);
-                boolean isSystem = res.pkg.applicationInfo.isSystemApp();
+                boolean isSystem = res.pkg.isSystemApp();
                 sendPackageAddedForNewUsers(packageName, isSystem || virtualPreload,
                         virtualPreload /*startReceiver*/, appId, firstUserIds, firstInstantUserIds);
 
@@ -2035,26 +2048,26 @@
                         final StorageManager storage = mInjector.getStorageManager();
                         VolumeInfo volume =
                                 storage.findVolumeByUuid(
-                                        res.pkg.applicationInfo.storageUuid.toString());
+                                        res.pkg.getStorageUuid().toString());
                         int packageExternalStorageType =
                                 getPackageExternalStorageType(volume, isExternal(res.pkg));
                         // If the package was installed externally, log it.
                         if (packageExternalStorageType != StorageEnums.UNKNOWN) {
                             StatsLog.write(StatsLog.APP_INSTALL_ON_EXTERNAL_STORAGE_REPORTED,
-                                    packageExternalStorageType, res.pkg.packageName);
+                                    packageExternalStorageType, res.pkg.getPackageName());
                         }
                     }
                     if (DEBUG_INSTALL) {
                         Slog.i(TAG, "upgrading pkg " + res.pkg + " is external");
                     }
-                    final int[] uidArray = new int[]{res.pkg.applicationInfo.uid};
+                    final int[] uidArray = new int[]{res.pkg.getUid()};
                     ArrayList<String> pkgList = new ArrayList<>(1);
                     pkgList.add(packageName);
                     sendResourcesChangedBroadcast(true, true, pkgList, uidArray, null);
                 }
             } else if (!ArrayUtils.isEmpty(res.libraryConsumers)) { // if static shared lib
                 for (int i = 0; i < res.libraryConsumers.size(); i++) {
-                    PackageParser.Package pkg = res.libraryConsumers.get(i);
+                    AndroidPackage pkg = res.libraryConsumers.get(i);
                     // send broadcast that all consumers of the static shared library have changed
                     sendPackageChangedBroadcast(pkg.packageName, false /* dontKillApp */,
                             new ArrayList<>(Collections.singletonList(pkg.packageName)),
@@ -2188,7 +2201,7 @@
 
     private void scheduleDeferredNoKillInstallObserver(PackageInstalledInfo info,
             IPackageInstallObserver2 observer) {
-        String packageName = info.pkg.packageName;
+        String packageName = info.pkg.getPackageName();
         mNoKillInstallObservers.put(packageName, Pair.create(info, observer));
         Message message = mHandler.obtainMessage(DEFERRED_NO_KILL_INSTALL_OBSERVER, packageName);
         mHandler.sendMessageDelayed(message, DEFERRED_NO_KILL_INSTALL_OBSERVER_DELAY_MS);
@@ -2783,11 +2796,11 @@
             final List<String> stubSystemApps = new ArrayList<>();
             if (!mOnlyCore) {
                 // do this first before mucking with mPackages for the "expecting better" case
-                final Iterator<PackageParser.Package> pkgIterator = mPackages.values().iterator();
+                final Iterator<AndroidPackage> pkgIterator = mPackages.values().iterator();
                 while (pkgIterator.hasNext()) {
-                    final PackageParser.Package pkg = pkgIterator.next();
-                    if (pkg.isStub) {
-                        stubSystemApps.add(pkg.packageName);
+                    final AndroidPackage pkg = pkgIterator.next();
+                    if (pkg.isStub()) {
+                        stubSystemApps.add(pkg.getPackageName());
                     }
                 }
 
@@ -2806,7 +2819,7 @@
                     /*
                      * If the package is scanned, it's not erased.
                      */
-                    final PackageParser.Package scannedPkg = mPackages.get(ps.name);
+                    final AndroidPackage scannedPkg = mPackages.get(ps.name);
                     if (scannedPkg != null) {
                         /*
                          * If the system app is both scanned and in the
@@ -2883,7 +2896,7 @@
                 // app completely. Otherwise, revoke their system privileges.
                 for (int i = possiblyDeletedUpdatedSystemApps.size() - 1; i >= 0; --i) {
                     final String packageName = possiblyDeletedUpdatedSystemApps.get(i);
-                    final PackageParser.Package pkg = mPackages.get(packageName);
+                    final AndroidPackage pkg = mPackages.get(packageName);
                     final String msg;
 
                     // remove from the disabled system list; do this first so any future
@@ -2909,7 +2922,7 @@
                         // special privileges
                         removePackageLI(pkg, true);
                         try {
-                            final File codePath = new File(pkg.applicationInfo.getCodePath());
+                            final File codePath = new File(pkg.getAppInfoCodePath());
                             scanPackageTracedLI(codePath, 0, scanFlags, 0, null);
                         } catch (PackageManagerException e) {
                             Slog.e(TAG, "Failed to parse updated, ex-system package: "
@@ -3105,7 +3118,7 @@
                 }
                 int count = 0;
                 for (String pkgName : deferPackages) {
-                    PackageParser.Package pkg = null;
+                    AndroidPackage pkg = null;
                     synchronized (mLock) {
                         PackageSetting ps = mSettings.getPackageLPr(pkgName);
                         if (ps != null && ps.getInstalled(UserHandle.USER_SYSTEM)) {
@@ -3205,12 +3218,12 @@
 
             // Initialize InstantAppRegistry's Instant App list for all users.
             final int[] userIds = UserManagerService.getInstance().getUserIds();
-            for (PackageParser.Package pkg : mPackages.values()) {
+            for (AndroidPackage pkg : mPackages.values()) {
                 if (pkg.isSystem()) {
                     continue;
                 }
                 for (int userId : userIds) {
-                    final PackageSetting ps = (PackageSetting) pkg.mExtras;
+                    final PackageSetting ps = getPackageSetting(pkg.getPackageName());
                     if (ps == null || !ps.getInstantApp(userId) || !ps.getInstalled(userId)) {
                         continue;
                     }
@@ -3297,7 +3310,7 @@
                 continue;
             }
             // skip if the package isn't installed (?!); this should never happen
-            final PackageParser.Package pkg = mPackages.get(packageName);
+            final AndroidPackage pkg = mPackages.get(packageName);
             if (pkg == null) {
                 systemStubPackageNames.remove(i);
                 continue;
@@ -3341,43 +3354,46 @@
      * APK will be installed and the package will be disabled. To recover from this situation,
      * the user will need to go into system settings and re-enable the package.
      */
-    private boolean enableCompressedPackage(PackageParser.Package stubPkg) {
+    private boolean enableCompressedPackage(AndroidPackage stubPkg) {
         final int parseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY
                 | PackageParser.PARSE_ENFORCE_CODE;
         synchronized (mInstallLock) {
-            final PackageParser.Package pkg;
+            final AndroidPackage pkg;
             try (PackageFreezer freezer =
-                    freezePackage(stubPkg.packageName, "setEnabledSetting")) {
+                    freezePackage(stubPkg.getPackageName(), "setEnabledSetting")) {
                 pkg = installStubPackageLI(stubPkg, parseFlags, 0 /*scanFlags*/);
                 synchronized (mLock) {
                     prepareAppDataAfterInstallLIF(pkg);
                     try {
-                        updateSharedLibrariesLocked(pkg, null, mPackages);
+                        updateSharedLibrariesLocked(pkg, null,
+                                Collections.unmodifiableMap(mPackages));
                     } catch (PackageManagerException e) {
                         Slog.e(TAG, "updateAllSharedLibrariesLPw failed: ", e);
                     }
-                    mPermissionManager.updatePermissions(pkg.packageName, pkg);
+                    mPermissionManager.updatePermissions(pkg.getPackageName(), pkg);
                     mSettings.writeLPr();
                 }
             } catch (PackageManagerException e) {
                 // Whoops! Something went very wrong; roll back to the stub and disable the package
                 try (PackageFreezer freezer =
-                        freezePackage(stubPkg.packageName, "setEnabledSetting")) {
+                        freezePackage(stubPkg.getPackageName(), "setEnabledSetting")) {
                     synchronized (mLock) {
                         // NOTE: Ensure the system package is enabled; even for a compressed stub.
                         // If we don't, installing the system package fails during scan
                         enableSystemPackageLPw(stubPkg);
                     }
-                    installPackageFromSystemLIF(stubPkg.codePath,
+                    installPackageFromSystemLIF(stubPkg.getCodePath(),
                             null /*allUserHandles*/, null /*origUserHandles*/,
                             null /*origPermissionsState*/, true /*writeSettings*/);
                 } catch (PackageManagerException pme) {
                     // Serious WTF; we have to be able to install the stub
-                    Slog.wtf(TAG, "Failed to restore system package:" + stubPkg.packageName, pme);
+                    Slog.wtf(TAG, "Failed to restore system package:" + stubPkg.getPackageName(),
+                            pme);
                 } finally {
                     // Disable the package; the stub by itself is not runnable
                     synchronized (mLock) {
-                        final PackageSetting stubPs = mSettings.mPackages.get(stubPkg.packageName);
+                        final PackageSetting stubPs = mSettings.mPackages.get(
+                                stubPkg.getPackageName());
                         if (stubPs != null) {
                             stubPs.setEnabled(COMPONENT_ENABLED_STATE_DISABLED,
                                     UserHandle.USER_SYSTEM, "android");
@@ -3389,31 +3405,33 @@
             }
             clearAppDataLIF(pkg, UserHandle.USER_ALL, FLAG_STORAGE_DE | FLAG_STORAGE_CE
                     | FLAG_STORAGE_EXTERNAL | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
-            mDexManager.notifyPackageUpdated(pkg.packageName,
-                    pkg.baseCodePath, pkg.splitCodePaths);
+            mDexManager.notifyPackageUpdated(pkg.getPackageName(),
+                    pkg.getBaseCodePath(), pkg.getSplitCodePaths());
         }
         return true;
     }
 
-    private PackageParser.Package installStubPackageLI(PackageParser.Package stubPkg,
+    private AndroidPackage installStubPackageLI(AndroidPackage stubPkg,
             @ParseFlags int parseFlags, @ScanFlags int scanFlags)
                     throws PackageManagerException {
         if (DEBUG_COMPRESSION) {
-            Slog.i(TAG, "Uncompressing system stub; pkg: " + stubPkg.packageName);
+            Slog.i(TAG, "Uncompressing system stub; pkg: " + stubPkg.getPackageName());
         }
         // uncompress the binary to its eventual destination on /data
-        final File scanFile = decompressPackage(stubPkg.packageName, stubPkg.codePath);
+        final File scanFile = decompressPackage(stubPkg.getPackageName(), stubPkg.getCodePath());
         if (scanFile == null) {
-            throw new PackageManagerException("Unable to decompress stub at " + stubPkg.codePath);
+            throw new PackageManagerException(
+                    "Unable to decompress stub at " + stubPkg.getCodePath());
         }
         synchronized (mLock) {
-            mSettings.disableSystemPackageLPw(stubPkg.packageName, true /*replaced*/);
+            mSettings.disableSystemPackageLPw(stubPkg.getPackageName(), true /*replaced*/);
         }
         removePackageLI(stubPkg, true /*chatty*/);
         try {
             return scanPackageTracedLI(scanFile, parseFlags, scanFlags, 0, null);
         } catch (PackageManagerException e) {
-            Slog.w(TAG, "Failed to install compressed system package:" + stubPkg.packageName, e);
+            Slog.w(TAG, "Failed to install compressed system package:" + stubPkg.getPackageName(),
+                    e);
             // Remove the failed install
             removeCodePathLI(scanFile);
             throw e;
@@ -3496,18 +3514,20 @@
     }
 
     private static @Nullable File preparePackageParserCache() {
-        if (!DEFAULT_PACKAGE_PARSER_CACHE_ENABLED) {
-            return null;
-        }
+        if (!FORCE_PACKAGE_PARSED_CACHE_ENABLED) {
+            if (!DEFAULT_PACKAGE_PARSER_CACHE_ENABLED) {
+                return null;
+            }
 
-        // Disable package parsing on eng builds to allow for faster incremental development.
-        if (Build.IS_ENG) {
-            return null;
-        }
+            // Disable package parsing on eng builds to allow for faster incremental development.
+            if (Build.IS_ENG) {
+                return null;
+            }
 
-        if (SystemProperties.getBoolean("pm.boot.disable_package_cache", false)) {
-            Slog.i(TAG, "Disabling package parser cache due to system property.");
-            return null;
+            if (SystemProperties.getBoolean("pm.boot.disable_package_cache", false)) {
+                Slog.i(TAG, "Disabling package parser cache due to system property.");
+                return null;
+            }
         }
 
         // The base directory for the package parser cache lives under /data/system/.
@@ -3519,10 +3539,12 @@
         // There are several items that need to be combined together to safely
         // identify cached items. In particular, changing the value of certain
         // feature flags should cause us to invalidate any caches.
-        final String cacheName = SystemProperties.digestOf(
-                "ro.build.fingerprint",
-                StorageManager.PROP_ISOLATED_STORAGE,
-                StorageManager.PROP_ISOLATED_STORAGE_SNAPSHOT);
+        final String cacheName = FORCE_PACKAGE_PARSED_CACHE_ENABLED ? "debug"
+                : SystemProperties.digestOf(
+                        "ro.build.fingerprint",
+                        StorageManager.PROP_ISOLATED_STORAGE,
+                        StorageManager.PROP_ISOLATED_STORAGE_SNAPSHOT
+                );
 
         // Reconcile cache directories, keeping only what we'd actually use.
         for (File cacheDir : FileUtils.listFilesOrEmpty(cacheBaseDir)) {
@@ -3846,7 +3868,7 @@
         ArraySet<String> packages = systemConfig.getLinkedApps();
 
         for (String packageName : packages) {
-            PackageParser.Package pkg = mPackages.get(packageName);
+            AndroidPackage pkg = mPackages.get(packageName);
             if (pkg != null) {
                 if (!pkg.isSystem()) {
                     Slog.w(TAG, "Non-system app '" + packageName + "' in sysconfig <app-link>");
@@ -3854,13 +3876,15 @@
                 }
 
                 ArraySet<String> domains = null;
-                for (PackageParser.Activity a : pkg.activities) {
-                    for (ActivityIntentInfo filter : a.intents) {
-                        if (hasValidDomains(filter)) {
-                            if (domains == null) {
-                                domains = new ArraySet<>();
+                if (pkg.getActivities() != null) {
+                    for (ParsedActivity a : pkg.getActivities()) {
+                        for (ParsedActivityIntentInfo filter : a.intents) {
+                            if (hasValidDomains(filter)) {
+                                if (domains == null) {
+                                    domains = new ArraySet<>();
+                                }
+                                domains.addAll(filter.getHostsList());
                             }
-                            domains.addAll(filter.getHostsList());
                         }
                     }
                 }
@@ -3976,7 +4000,7 @@
         }
 
         final PackageUserState state = ps.readUserState(userId);
-        PackageParser.Package p = ps.pkg;
+        AndroidPackage p = ps.pkg;
         if (p != null) {
             final PermissionsState permissionsState = ps.getPermissionsState();
 
@@ -3984,10 +4008,10 @@
             final int[] gids = (flags & PackageManager.GET_GIDS) == 0
                     ? EMPTY_INT_ARRAY : permissionsState.computeGids(userId);
             // Compute granted permissions only if package has requested permissions
-            final Set<String> permissions = ArrayUtils.isEmpty(p.requestedPermissions)
+            final Set<String> permissions = ArrayUtils.isEmpty(p.getRequestedPermissions())
                     ? Collections.emptySet() : permissionsState.getPermissions(userId);
 
-            PackageInfo packageInfo = PackageParser.generatePackageInfo(p, gids, flags,
+            PackageInfo packageInfo = PackageInfoUtils.generate(p, gids, flags,
                     ps.firstInstallTime, ps.lastUpdateTime, permissions, state, userId);
 
             if (packageInfo == null) {
@@ -4050,7 +4074,7 @@
                 throw new SecurityException("Package " + packageName + " is currently frozen!");
             }
 
-            if (!userKeyUnlocked && !ps.pkg.applicationInfo.isEncryptionAware()) {
+            if (!userKeyUnlocked && !ps.pkg.isEncryptionAware()) {
                 throw new SecurityException("Package " + packageName + " is not encryption aware!");
             }
         }
@@ -4063,9 +4087,9 @@
         mPermissionManager.enforceCrossUserPermission(callingUid, userId,
                 false /*requireFullPermission*/, false /*checkShell*/, "is package available");
         synchronized (mLock) {
-            PackageParser.Package p = mPackages.get(packageName);
+            AndroidPackage p = mPackages.get(packageName);
             if (p != null) {
-                final PackageSetting ps = (PackageSetting) p.mExtras;
+                final PackageSetting ps = getPackageSetting(p.getPackageName());
                 if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
                     return false;
                 }
@@ -4130,21 +4154,22 @@
                 }
             }
 
-            PackageParser.Package p = mPackages.get(packageName);
+            AndroidPackage p = mPackages.get(packageName);
             if (matchFactoryOnly && p != null && !isSystemApp(p)) {
                 return null;
             }
             if (DEBUG_PACKAGE_INFO)
                 Log.v(TAG, "getPackageInfo " + packageName + ": " + p);
             if (p != null) {
-                final PackageSetting ps = (PackageSetting) p.mExtras;
+                final PackageSetting ps = getPackageSetting(p.getPackageName());
                 if (filterSharedLibPackageLPr(ps, filterCallingUid, userId, flags)) {
                     return null;
                 }
                 if (ps != null && shouldFilterApplicationLocked(ps, filterCallingUid, userId)) {
                     return null;
                 }
-                return generatePackageInfo((PackageSetting)p.mExtras, flags, userId);
+
+                return generatePackageInfo(ps, flags, userId);
             }
             if (!matchFactoryOnly && (flags & MATCH_KNOWN_PACKAGES) != 0) {
                 final PackageSetting ps = mSettings.mPackages.get(packageName);
@@ -4180,34 +4205,34 @@
     private boolean isComponentVisibleToInstantApp(
             @Nullable ComponentName component, @ComponentType int type) {
         if (type == TYPE_ACTIVITY) {
-            final PackageParser.Activity activity = mComponentResolver.getActivity(component);
+            final ParsedActivity activity = mComponentResolver.getActivity(component);
             if (activity == null) {
                 return false;
             }
             final boolean visibleToInstantApp =
-                    (activity.info.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0;
+                    (activity.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0;
             final boolean explicitlyVisibleToInstantApp =
-                    (activity.info.flags & ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP) == 0;
+                    (activity.flags & ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP) == 0;
             return visibleToInstantApp && explicitlyVisibleToInstantApp;
         } else if (type == TYPE_RECEIVER) {
-            final PackageParser.Activity activity = mComponentResolver.getReceiver(component);
+            final ParsedActivity activity = mComponentResolver.getReceiver(component);
             if (activity == null) {
                 return false;
             }
             final boolean visibleToInstantApp =
-                    (activity.info.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0;
+                    (activity.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0;
             final boolean explicitlyVisibleToInstantApp =
-                    (activity.info.flags & ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP) == 0;
+                    (activity.flags & ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP) == 0;
             return visibleToInstantApp && !explicitlyVisibleToInstantApp;
         } else if (type == TYPE_SERVICE) {
-            final PackageParser.Service service = mComponentResolver.getService(component);
+            final ParsedService service = mComponentResolver.getService(component);
             return service != null
-                    ? (service.info.flags & ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0
+                    ? (service.flags & ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0
                     : false;
         } else if (type == TYPE_PROVIDER) {
-            final PackageParser.Provider provider = mComponentResolver.getProvider(component);
+            final ParsedProvider provider = mComponentResolver.getProvider(component);
             return provider != null
-                    ? (provider.info.flags & ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0
+                    ? (provider.getFlags() & ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0
                     : false;
         } else if (type == TYPE_UNKNOWN) {
             return isComponentVisibleToInstantApp(component);
@@ -4251,16 +4276,16 @@
             // request for a specific component; if it hasn't been explicitly exposed through
             // property or instrumentation target, filter
             if (component != null) {
-                final PackageParser.Instrumentation instrumentation =
+                final ParsedInstrumentation instrumentation =
                         mInstrumentation.get(component);
                 if (instrumentation != null
-                        && isCallerSameApp(instrumentation.info.targetPackage, callingUid)) {
+                        && isCallerSameApp(instrumentation.getTargetPackage(), callingUid)) {
                     return false;
                 }
                 return !isComponentVisibleToInstantApp(component, componentType);
             }
             // request for application; if no components have been explicitly exposed, filter
-            return !ps.pkg.visibleToInstantApps;
+            return !ps.pkg.isVisibleToInstantApps();
         }
         if (ps.getInstantApp(userId)) {
             // caller can see all components of all instant applications, don't filter
@@ -4309,12 +4334,12 @@
         }
 
         // No package means no static lib as it is always on internal storage
-        if (ps == null || ps.pkg == null || !ps.pkg.applicationInfo.isStaticSharedLibrary()) {
+        if (ps == null || ps.pkg == null || !ps.pkg.isStaticSharedLibrary()) {
             return false;
         }
 
-        final SharedLibraryInfo libraryInfo = getSharedLibraryInfoLPr(ps.pkg.staticSharedLibName,
-                ps.pkg.staticSharedLibVersion);
+        final SharedLibraryInfo libraryInfo = getSharedLibraryInfoLPr(
+                ps.pkg.getStaticSharedLibName(), ps.pkg.getStaticSharedLibVersion());
         if (libraryInfo == null) {
             return false;
         }
@@ -4336,7 +4361,8 @@
                 if (index < 0) {
                     continue;
                 }
-                if (uidPs.pkg.usesStaticLibrariesVersions[index] == libraryInfo.getLongVersion()) {
+                if (uidPs.pkg.getUsesStaticLibrariesVersions()[index]
+                        == libraryInfo.getLongVersion()) {
                     return false;
                 }
             }
@@ -4410,13 +4436,13 @@
 
         // reader
         synchronized (mLock) {
-            final PackageParser.Package p = mPackages.get(packageName);
+            final AndroidPackage p = mPackages.get(packageName);
             if (p != null && p.isMatch(flags)) {
-                PackageSetting ps = (PackageSetting) p.mExtras;
+                PackageSetting ps = getPackageSetting(p.getPackageName());
                 if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
                     return -1;
                 }
-                return UserHandle.getUid(userId, p.applicationInfo.uid);
+                return UserHandle.getUid(userId, p.getUid());
             }
             if ((flags & MATCH_KNOWN_PACKAGES) != 0) {
                 final PackageSetting ps = mSettings.mPackages.get(packageName);
@@ -4440,9 +4466,9 @@
 
         // reader
         synchronized (mLock) {
-            final PackageParser.Package p = mPackages.get(packageName);
+            final AndroidPackage p = mPackages.get(packageName);
             if (p != null && p.isMatch(flags)) {
-                PackageSetting ps = (PackageSetting) p.mExtras;
+                PackageSetting ps = getPackageSetting(p.getPackageName());
                 if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
                     return null;
                 }
@@ -4492,7 +4518,7 @@
                 }
                 return null;
             }
-            ApplicationInfo ai = PackageParser.generateApplicationInfo(ps.pkg, flags,
+            ApplicationInfo ai = PackageInfoUtils.generateApplicationInfo(ps.pkg, flags,
                     ps.readUserState(userId), userId);
             if (ai != null) {
                 ai.packageName = resolveExternalPackageNameLPr(ps.pkg);
@@ -4530,7 +4556,7 @@
             packageName = resolveInternalPackageNameLPr(packageName,
                     PackageManager.VERSION_CODE_HIGHEST);
 
-            PackageParser.Package p = mPackages.get(packageName);
+            AndroidPackage p = mPackages.get(packageName);
             if (DEBUG_PACKAGE_INFO) Log.v(
                     TAG, "getApplicationInfo " + packageName
                     + ": " + p);
@@ -4544,7 +4570,7 @@
                     return null;
                 }
                 // Note: isEnabledLP() does not apply here - always return info
-                ApplicationInfo ai = PackageParser.generateApplicationInfo(
+                ApplicationInfo ai = PackageInfoUtils.generateApplicationInfo(
                         p, flags, ps.readUserState(userId), userId);
                 if (ai != null) {
                     ai.packageName = resolveExternalPackageNameLPr(p);
@@ -4916,17 +4942,19 @@
         }
 
         synchronized (mLock) {
-            PackageParser.Activity a = mComponentResolver.getActivity(component);
+            ParsedActivity a = mComponentResolver.getActivity(component);
 
             if (DEBUG_PACKAGE_INFO) Log.v(TAG, "getActivityInfo " + component + ": " + a);
-            if (a != null && mSettings.isEnabledAndMatchLPr(a.info, flags, userId)) {
+
+            AndroidPackage pkg = a == null ? null : mPackages.get(a.getPackageName());
+            if (pkg != null && mSettings.isEnabledAndMatchLPr(pkg, a, flags, userId)) {
                 PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
                 if (ps == null) return null;
                 if (shouldFilterApplicationLocked(
                         ps, filterCallingUid, component, TYPE_ACTIVITY, userId)) {
                     return null;
                 }
-                return PackageParser.generateActivityInfo(
+                return PackageInfoUtils.generateActivityInfo(pkg,
                         a, flags, ps.readUserState(userId), userId);
             }
             if (mResolveComponentName.equals(component)) {
@@ -4963,7 +4991,7 @@
             }
             final int callingUid = Binder.getCallingUid();
             final int callingUserId = UserHandle.getUserId(callingUid);
-            PackageParser.Activity a = mComponentResolver.getActivity(component);
+            ParsedActivity a = mComponentResolver.getActivity(component);
             if (a == null) {
                 return false;
             }
@@ -4993,17 +5021,27 @@
         mPermissionManager.enforceCrossUserPermission(callingUid, userId,
                 false /* requireFullPermission */, false /* checkShell */, "get receiver info");
         synchronized (mLock) {
-            PackageParser.Activity a = mComponentResolver.getReceiver(component);
+            ParsedActivity a = mComponentResolver.getReceiver(component);
             if (DEBUG_PACKAGE_INFO) Log.v(
                 TAG, "getReceiverInfo " + component + ": " + a);
-            if (a != null && mSettings.isEnabledAndMatchLPr(a.info, flags, userId)) {
+
+            if (a == null) {
+                return null;
+            }
+
+            AndroidPackage pkg = mPackages.get(a.getPackageName());
+            if (pkg == null) {
+                return null;
+            }
+
+            if (mSettings.isEnabledAndMatchLPr(pkg, a, flags, userId)) {
                 PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
                 if (ps == null) return null;
                 if (shouldFilterApplicationLocked(
                         ps, callingUid, component, TYPE_RECEIVER, userId)) {
                     return null;
                 }
-                return PackageParser.generateActivityInfo(
+                return PackageInfoUtils.generateActivityInfo(pkg,
                         a, flags, ps.readUserState(userId), userId);
             }
         }
@@ -5182,13 +5220,13 @@
                 }
                 // If the dependent is a static shared lib, use the public package name
                 String dependentPackageName = ps.name;
-                if (ps.pkg != null && ps.pkg.applicationInfo.isStaticSharedLibrary()) {
-                    dependentPackageName = ps.pkg.manifestPackageName;
+                if (ps.pkg != null && ps.pkg.isStaticSharedLibrary()) {
+                    dependentPackageName = ps.pkg.getManifestPackageName();
                 }
                 versionedPackages.add(new VersionedPackage(dependentPackageName, ps.versionCode));
             } else if (ps.pkg != null) {
-                if (ArrayUtils.contains(ps.pkg.usesLibraries, libName)
-                        || ArrayUtils.contains(ps.pkg.usesOptionalLibraries, libName)) {
+                if (ArrayUtils.contains(ps.pkg.getUsesLibraries(), libName)
+                        || ArrayUtils.contains(ps.pkg.getUsesOptionalLibraries(), libName)) {
                     if (versionedPackages == null) {
                         versionedPackages = new ArrayList<>();
                     }
@@ -5208,17 +5246,22 @@
         mPermissionManager.enforceCrossUserPermission(callingUid, userId,
                 false /* requireFullPermission */, false /* checkShell */, "get service info");
         synchronized (mLock) {
-            PackageParser.Service s = mComponentResolver.getService(component);
+            ParsedService s = mComponentResolver.getService(component);
             if (DEBUG_PACKAGE_INFO) Log.v(
-                TAG, "getServiceInfo " + component + ": " + s);
-            if (s != null && mSettings.isEnabledAndMatchLPr(s.info, flags, userId)) {
+                    TAG, "getServiceInfo " + component + ": " + s);
+            if (s == null) {
+                return null;
+            }
+
+            AndroidPackage pkg = mPackages.get(s.getPackageName());
+            if (mSettings.isEnabledAndMatchLPr(pkg, s, flags, userId)) {
                 PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
                 if (ps == null) return null;
                 if (shouldFilterApplicationLocked(
                         ps, callingUid, component, TYPE_SERVICE, userId)) {
                     return null;
                 }
-                return PackageParser.generateServiceInfo(
+                return PackageInfoUtils.generateServiceInfo(pkg,
                         s, flags, ps.readUserState(userId), userId);
             }
         }
@@ -5233,18 +5276,27 @@
         mPermissionManager.enforceCrossUserPermission(callingUid, userId,
                 false /* requireFullPermission */, false /* checkShell */, "get provider info");
         synchronized (mLock) {
-            PackageParser.Provider p = mComponentResolver.getProvider(component);
+            ParsedProvider p = mComponentResolver.getProvider(component);
             if (DEBUG_PACKAGE_INFO) Log.v(
-                TAG, "getProviderInfo " + component + ": " + p);
-            if (p != null && mSettings.isEnabledAndMatchLPr(p.info, flags, userId)) {
+                    TAG, "getProviderInfo " + component + ": " + p);
+            if (p == null) {
+                return null;
+            }
+
+            AndroidPackage pkg = mPackages.get(p.getPackageName());
+            if (pkg == null) {
+                return null;
+            }
+
+            if (mSettings.isEnabledAndMatchLPr(pkg, p, flags, userId)) {
                 PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
                 if (ps == null) return null;
                 if (shouldFilterApplicationLocked(
                         ps, callingUid, component, TYPE_PROVIDER, userId)) {
                     return null;
                 }
-                return PackageParser.generateProviderInfo(
-                        p, flags, ps.readUserState(userId), userId);
+                PackageUserState state = ps.readUserState(userId);
+                return PackageInfoUtils.generateProviderInfo(pkg, p, flags, state, userId);
             }
         }
         return null;
@@ -5502,21 +5554,21 @@
     @Override
     public int checkSignatures(String pkg1, String pkg2) {
         synchronized (mLock) {
-            final PackageParser.Package p1 = mPackages.get(pkg1);
-            final PackageParser.Package p2 = mPackages.get(pkg2);
-            if (p1 == null || p1.mExtras == null
-                    || p2 == null || p2.mExtras == null) {
+            final AndroidPackage p1 = mPackages.get(pkg1);
+            final AndroidPackage p2 = mPackages.get(pkg2);
+            final PackageSetting ps1 = p1 == null ? null : getPackageSetting(p1.getPackageName());
+            final PackageSetting ps2 = p2 == null ? null : getPackageSetting(p2.getPackageName());
+            if (p1 == null || ps1 == null || p2 == null || ps2 == null) {
                 return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
             }
             final int callingUid = Binder.getCallingUid();
             final int callingUserId = UserHandle.getUserId(callingUid);
-            final PackageSetting ps1 = (PackageSetting) p1.mExtras;
-            final PackageSetting ps2 = (PackageSetting) p2.mExtras;
             if (shouldFilterApplicationLocked(ps1, callingUid, callingUserId)
                     || shouldFilterApplicationLocked(ps2, callingUid, callingUserId)) {
                 return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
             }
-            return compareSignatures(p1.mSigningDetails.signatures, p2.mSigningDetails.signatures);
+            return compareSignatures(p1.getSigningDetails().signatures,
+                    p2.getSigningDetails().signatures);
         }
     }
 
@@ -5579,21 +5631,21 @@
             String packageName, byte[] certificate, @PackageManager.CertificateInputType int type) {
 
         synchronized (mLock) {
-            final PackageParser.Package p = mPackages.get(packageName);
-            if (p == null || p.mExtras == null) {
+            final AndroidPackage p = mPackages.get(packageName);
+            final PackageSetting ps = getPackageSetting(p.getPackageName());
+            if (p == null || ps == null) {
                 return false;
             }
             final int callingUid = Binder.getCallingUid();
             final int callingUserId = UserHandle.getUserId(callingUid);
-            final PackageSetting ps = (PackageSetting) p.mExtras;
             if (shouldFilterApplicationLocked(ps, callingUid, callingUserId)) {
                 return false;
             }
             switch (type) {
                 case CERT_INPUT_RAW_X509:
-                    return p.mSigningDetails.hasCertificate(certificate);
+                    return p.getSigningDetails().hasCertificate(certificate);
                 case CERT_INPUT_SHA256:
-                    return p.mSigningDetails.hasSha256Certificate(certificate);
+                    return p.getSigningDetails().hasSha256Certificate(certificate);
                 default:
                     return false;
             }
@@ -5646,16 +5698,16 @@
      * external storage) is less than the version where package signatures
      * were updated, return true.
      */
-    private boolean isCompatSignatureUpdateNeeded(PackageParser.Package scannedPkg) {
-        return isCompatSignatureUpdateNeeded(getSettingsVersionForPackage(scannedPkg));
+    private boolean isCompatSignatureUpdateNeeded(AndroidPackage pkg) {
+        return isCompatSignatureUpdateNeeded(getSettingsVersionForPackage(pkg));
     }
 
     private static boolean isCompatSignatureUpdateNeeded(VersionInfo ver) {
         return ver.databaseVersion < DatabaseVersion.SIGNATURE_END_ENTITY;
     }
 
-    private boolean isRecoverSignatureUpdateNeeded(PackageParser.Package scannedPkg) {
-        return isRecoverSignatureUpdateNeeded(getSettingsVersionForPackage(scannedPkg));
+    private boolean isRecoverSignatureUpdateNeeded(AndroidPackage pkg) {
+        return isRecoverSignatureUpdateNeeded(getSettingsVersionForPackage(pkg));
     }
 
     private static boolean isRecoverSignatureUpdateNeeded(VersionInfo ver) {
@@ -5674,24 +5726,23 @@
             final List<String> result = new ArrayList<>();
             if (instantAppPkgName != null) {
                 // caller is an instant application; filter unexposed applications
-                for (PackageParser.Package pkg : mPackages.values()) {
-                    if (!pkg.visibleToInstantApps) {
+                for (AndroidPackage pkg : mPackages.values()) {
+                    if (!pkg.isVisibleToInstantApps()) {
                         continue;
                     }
-                    result.add(pkg.packageName);
+                    result.add(pkg.getPackageName());
                 }
             } else {
                 // caller is a normal application; filter instant applications
-                for (PackageParser.Package pkg : mPackages.values()) {
-                    final PackageSetting ps =
-                            pkg.mExtras != null ? (PackageSetting) pkg.mExtras : null;
+                for (AndroidPackage pkg : mPackages.values()) {
+                    final PackageSetting ps = getPackageSetting(pkg.getPackageName());
                     if (ps != null
                             && ps.getInstantApp(callingUserId)
                             && !mInstantAppRegistry.isInstantAccessGranted(
                                     callingUserId, UserHandle.getAppId(callingUid), ps.appId)) {
                         continue;
                     }
-                    result.add(pkg.packageName);
+                    result.add(pkg.getPackageName());
                 }
             }
             return result;
@@ -6535,7 +6586,7 @@
             if (obj instanceof PackageSetting) {
                 final PackageSetting ps = (PackageSetting) obj;
                 final boolean isInstantApp = ps.getInstantApp(UserHandle.getUserId(callingUid));
-                return isInstantApp ? ps.pkg.packageName : null;
+                return isInstantApp ? ps.pkg.getPackageName() : null;
             }
         }
         return null;
@@ -6607,9 +6658,11 @@
                     list.add(ri);
                 }
             }
-            return applyPostResolutionFilter(
+
+            List<ResolveInfo> result = applyPostResolutionFilter(
                     list, instantAppPkgName, allowDynamicSplits, filterCallingUid, resolveForStart,
                     userId, intent);
+            return result;
         }
 
         // reader
@@ -6686,11 +6739,11 @@
                     sortResult = true;
                 }
             } else {
-                final PackageParser.Package pkg = mPackages.get(pkgName);
+                final AndroidPackage pkg = mPackages.get(pkgName);
                 result = null;
                 if (pkg != null) {
                     result = filterIfNotSystemUser(mComponentResolver.queryActivities(
-                            intent, resolvedType, flags, pkg.activities, userId), userId);
+                            intent, resolvedType, flags, pkg.getActivities(), userId), userId);
                 }
                 if (result == null || result.size() == 0) {
                     // the caller wants to resolve for a particular package; however, there
@@ -7584,7 +7637,7 @@
                         result, instantAppPkgName, allowDynamicSplits, callingUid, false, userId,
                         intent);
             }
-            final PackageParser.Package pkg = mPackages.get(pkgName);
+            final AndroidPackage pkg = mPackages.get(pkgName);
             if (pkg != null) {
                 final List<ResolveInfo> result = mComponentResolver.queryReceivers(
                         intent, resolvedType, flags, pkg.receivers, userId);
@@ -7693,7 +7746,7 @@
                         resolveInfos,
                         instantAppPkgName);
             }
-            final PackageParser.Package pkg = mPackages.get(pkgName);
+            final AndroidPackage pkg = mPackages.get(pkgName);
             if (pkg != null) {
                 final List<ResolveInfo> resolveInfos = mComponentResolver.queryServices(intent,
                         resolvedType, flags, pkg.services,
@@ -7820,7 +7873,7 @@
                         resolveInfos,
                         instantAppPkgName);
             }
-            final PackageParser.Package pkg = mPackages.get(pkgName);
+            final AndroidPackage pkg = mPackages.get(pkgName);
             if (pkg != null) {
                 final List<ResolveInfo> resolveInfos = mComponentResolver.queryProviders(intent,
                         resolvedType, flags,
@@ -7914,16 +7967,15 @@
                 }
             } else {
                 list = new ArrayList<>(mPackages.size());
-                for (PackageParser.Package p : mPackages.values()) {
-                    final PackageSetting ps = (PackageSetting) p.mExtras;
+                for (AndroidPackage p : mPackages.values()) {
+                    final PackageSetting ps = getPackageSetting(p.getPackageName());
                     if (filterSharedLibPackageLPr(ps, callingUid, userId, flags)) {
                         continue;
                     }
                     if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
                         continue;
                     }
-                    final PackageInfo pi = generatePackageInfo((PackageSetting)
-                            p.mExtras, flags, userId);
+                    final PackageInfo pi = generatePackageInfo(ps, flags, userId);
                     if (pi != null) {
                         list.add(pi);
                     }
@@ -8002,8 +8054,8 @@
                             userId);
                 }
             } else {
-                for (PackageParser.Package pkg : mPackages.values()) {
-                    PackageSetting ps = (PackageSetting)pkg.mExtras;
+                for (AndroidPackage pkg : mPackages.values()) {
+                    PackageSetting ps = getPackageSetting(pkg.getPackageName());
                     if (ps != null) {
                         addPackageHoldingPermissions(list, ps, permissions, tmpBools, flags,
                                 userId);
@@ -8056,7 +8108,7 @@
                         if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
                             continue;
                         }
-                        ai = PackageParser.generateApplicationInfo(ps.pkg, effectiveFlags,
+                        ai = PackageInfoUtils.generateApplicationInfo(ps.pkg, effectiveFlags,
                                 ps.readUserState(userId), userId);
                         if (ai != null) {
                             ai.packageName = resolveExternalPackageNameLPr(ps.pkg);
@@ -8073,16 +8125,16 @@
                 }
             } else {
                 list = new ArrayList<>(mPackages.size());
-                for (PackageParser.Package p : mPackages.values()) {
-                    if (p.mExtras != null) {
-                        PackageSetting ps = (PackageSetting) p.mExtras;
+                for (AndroidPackage p : mPackages.values()) {
+                    final PackageSetting ps = getPackageSetting(p.getPackageName());
+                    if (ps != null) {
                         if (filterSharedLibPackageLPr(ps, Binder.getCallingUid(), userId, flags)) {
                             continue;
                         }
                         if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
                             continue;
                         }
-                        ApplicationInfo ai = PackageParser.generateApplicationInfo(p, flags,
+                        ApplicationInfo ai = PackageInfoUtils.generateApplicationInfo(p, flags,
                                 ps.readUserState(userId), userId);
                         if (ai != null) {
                             ai.packageName = resolveExternalPackageNameLPr(p);
@@ -8138,7 +8190,6 @@
                 callingUid = mIsolatedOwners.get(callingUid);
             }
             final PackageSetting ps = mSettings.mPackages.get(packageName);
-            PackageParser.Package pkg = mPackages.get(packageName);
             final boolean returnAllowed =
                     ps != null
                     && (isCallerSameApp(packageName, callingUid)
@@ -8209,9 +8260,9 @@
     }
 
     private boolean isCallerSameApp(String packageName, int uid) {
-        PackageParser.Package pkg = mPackages.get(packageName);
+        AndroidPackage pkg = mPackages.get(packageName);
         return pkg != null
-                && UserHandle.getAppId(uid) == pkg.applicationInfo.uid;
+                && UserHandle.getAppId(uid) == pkg.getUid();
     }
 
     @Override
@@ -8227,23 +8278,22 @@
 
         // reader
         synchronized (mLock) {
-            final Iterator<PackageParser.Package> i = mPackages.values().iterator();
+            final Iterator<AndroidPackage> i = mPackages.values().iterator();
             final int userId = UserHandle.getCallingUserId();
             while (i.hasNext()) {
-                final PackageParser.Package p = i.next();
-                if (p.applicationInfo == null) continue;
+                final AndroidPackage p = i.next();
 
                 final boolean matchesUnaware = ((flags & MATCH_DIRECT_BOOT_UNAWARE) != 0)
-                        && !p.applicationInfo.isDirectBootAware();
+                        && !p.isDirectBootAware();
                 final boolean matchesAware = ((flags & MATCH_DIRECT_BOOT_AWARE) != 0)
-                        && p.applicationInfo.isDirectBootAware();
+                        && p.isDirectBootAware();
 
-                if ((p.applicationInfo.flags & ApplicationInfo.FLAG_PERSISTENT) != 0
+                if ((p.getFlags() & ApplicationInfo.FLAG_PERSISTENT) != 0
                         && (!mSafeMode || isSystemApp(p))
                         && (matchesUnaware || matchesAware)) {
-                    PackageSetting ps = mSettings.mPackages.get(p.packageName);
+                    PackageSetting ps = mSettings.mPackages.get(p.getPackageName());
                     if (ps != null) {
-                        ApplicationInfo ai = PackageParser.generateApplicationInfo(p, flags,
+                        ApplicationInfo ai = PackageInfoUtils.generateApplicationInfo(p, flags,
                                 ps.readUserState(userId), userId);
                         if (ai != null) {
                             finalList.add(ai);
@@ -8265,7 +8315,8 @@
         if (!mUserManager.exists(userId)) return null;
         flags = updateFlagsForComponent(flags, userId);
         final int callingUid = Binder.getCallingUid();
-        final ProviderInfo providerInfo = mComponentResolver.queryProvider(name, flags, userId);
+        final ProviderInfo providerInfo = mComponentResolver.queryProvider(name, flags, callingUid,
+                userId);
         if (providerInfo == null) {
             return null;
         }
@@ -8347,8 +8398,8 @@
                     ps, callingUid, component, TYPE_UNKNOWN, callingUserId)) {
                 return null;
             }
-            final PackageParser.Instrumentation i = mInstrumentation.get(component);
-            return PackageParser.generateInstrumentationInfo(i, flags);
+            final ParsedInstrumentation i = mInstrumentation.get(component);
+            return PackageInfoUtils.generateInstrumentationInfo(i, flags);
         }
     }
 
@@ -8370,12 +8421,12 @@
 
         // reader
         synchronized (mLock) {
-            final Iterator<PackageParser.Instrumentation> i = mInstrumentation.values().iterator();
+            final Iterator<ParsedInstrumentation> i = mInstrumentation.values().iterator();
             while (i.hasNext()) {
-                final PackageParser.Instrumentation p = i.next();
+                final ParsedInstrumentation p = i.next();
                 if (targetPackage == null
-                        || targetPackage.equals(p.info.targetPackage)) {
-                    InstrumentationInfo ii = PackageParser.generateInstrumentationInfo(p,
+                        || targetPackage.equals(p.getTargetPackage())) {
+                    InstrumentationInfo ii = PackageInfoUtils.generateInstrumentationInfo(p,
                             flags);
                     if (ii != null) {
                         finalList.add(ii);
@@ -8432,18 +8483,18 @@
                 if (throwable == null) {
                     // TODO(toddke): move lower in the scan chain
                     // Static shared libraries have synthetic package names
-                    if (parseResult.pkg.applicationInfo.isStaticSharedLibrary()) {
-                        renameStaticSharedLibraryPackage(parseResult.pkg);
+                    if (parseResult.parsedPackage.isStaticSharedLibrary()) {
+                        renameStaticSharedLibraryPackage(parseResult.parsedPackage);
                     }
                     try {
-                        scanPackageChildLI(parseResult.pkg, parseFlags, scanFlags,
+                        addForInitLI(parseResult.parsedPackage, parseFlags, scanFlags,
                                 currentTime, null);
                     } catch (PackageManagerException e) {
                         errorCode = e.error;
                         Slog.w(TAG, "Failed to scan " + parseResult.scanFile + ": " + e.getMessage());
                     }
-                } else if (throwable instanceof PackageParser.PackageParserException) {
-                    PackageParser.PackageParserException e = (PackageParser.PackageParserException)
+                } else if (throwable instanceof PackageParserException) {
+                    PackageParserException e = (PackageParserException)
                             throwable;
                     errorCode = e.error;
                     Slog.w(TAG, "Failed to parse " + parseResult.scanFile + ": " + e.getMessage());
@@ -8467,15 +8518,16 @@
         logCriticalInfo(priority, msg);
     }
 
-    private void collectCertificatesLI(PackageSetting ps, PackageParser.Package pkg,
+    private void collectCertificatesLI(PackageSetting ps, ParsedPackage parsedPackage,
             boolean forceCollect, boolean skipVerify) throws PackageManagerException {
         // When upgrading from pre-N MR1, verify the package time stamp using the package
         // directory and not the APK file.
         final long lastModifiedTime = mIsPreNMR1Upgrade
-                ? new File(pkg.codePath).lastModified() : getLastModifiedTime(pkg);
-        final VersionInfo settingsVersionForPackage = getSettingsVersionForPackage(pkg);
+                ? new File(parsedPackage.getCodePath()).lastModified()
+                : getLastModifiedTime(parsedPackage);
+        final VersionInfo settingsVersionForPackage = getSettingsVersionForPackage(parsedPackage);
         if (ps != null && !forceCollect
-                && ps.codePathString.equals(pkg.codePath)
+                && ps.codePathString.equals(parsedPackage.getCodePath())
                 && ps.timeStamp == lastModifiedTime
                 && !isCompatSignatureUpdateNeeded(settingsVersionForPackage)
                 && !isRecoverSignatureUpdateNeeded(settingsVersionForPackage)) {
@@ -8485,21 +8537,21 @@
                             != SignatureSchemeVersion.UNKNOWN) {
                 // Optimization: reuse the existing cached signing data
                 // if the package appears to be unchanged.
-                pkg.mSigningDetails =
-                        new PackageParser.SigningDetails(ps.signatures.mSigningDetails);
+                parsedPackage.setSigningDetails(
+                        new PackageParser.SigningDetails(ps.signatures.mSigningDetails));
                 return;
             }
 
             Slog.w(TAG, "PackageSetting for " + ps.name
                     + " is missing signatures.  Collecting certs again to recover them.");
         } else {
-            Slog.i(TAG, pkg.codePath + " changed; collecting certs" +
+            Slog.i(TAG, parsedPackage.getCodePath() + " changed; collecting certs" +
                     (forceCollect ? " (forced)" : ""));
         }
 
         try {
             Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates");
-            PackageParser.collectCertificates(pkg, skipVerify);
+            ApkParseUtils.collectCertificates(parsedPackage, skipVerify);
         } catch (PackageParserException e) {
             throw PackageManagerException.from(e);
         } finally {
@@ -8513,20 +8565,20 @@
      */
     private void maybeClearProfilesForUpgradesLI(
             @Nullable PackageSetting originalPkgSetting,
-            @NonNull PackageParser.Package currentPkg) {
+            @NonNull AndroidPackage pkg) {
         if (originalPkgSetting == null || !isDeviceUpgrading()) {
           return;
         }
-        if (originalPkgSetting.versionCode == currentPkg.mVersionCode) {
+        if (originalPkgSetting.versionCode == pkg.getVersionCode()) {
           return;
         }
 
-        clearAppProfilesLIF(currentPkg, UserHandle.USER_ALL);
+        clearAppProfilesLIF(pkg, UserHandle.USER_ALL);
         if (DEBUG_INSTALL) {
             Slog.d(TAG, originalPkgSetting.name
                   + " clear profile due to version change "
                   + originalPkgSetting.versionCode + " != "
-                  + currentPkg.mVersionCode);
+                  + pkg.getVersionCode());
         }
     }
 
@@ -8535,7 +8587,7 @@
      *  @see #scanPackageLI(File, int, int, long, UserHandle)
      */
     @GuardedBy({"mInstallLock", "mLock"})
-    private PackageParser.Package scanPackageTracedLI(File scanFile, final int parseFlags,
+    private AndroidPackage scanPackageTracedLI(File scanFile, final int parseFlags,
             int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {
         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanPackage [" + scanFile.toString() + "]");
         try {
@@ -8550,7 +8602,7 @@
      *  Returns {@code null} in case of errors and the error code is stored in mLastScanError
      */
     @GuardedBy({"mInstallLock", "mLock"})
-    private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanFlags,
+    private AndroidPackage scanPackageLI(File scanFile, int parseFlags, int scanFlags,
             long currentTime, UserHandle user) throws PackageManagerException {
         if (DEBUG_INSTALL) Slog.d(TAG, "Parsing: " + scanFile);
         PackageParser pp = new PackageParser();
@@ -8560,9 +8612,9 @@
         pp.setCallback(mPackageParserCallback);
 
         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");
-        final PackageParser.Package pkg;
+        final ParsedPackage parsedPackage;
         try {
-            pkg = pp.parsePackage(scanFile, parseFlags);
+            parsedPackage = pp.parseParsedPackage(scanFile, parseFlags, false);
         } catch (PackageParserException e) {
             throw PackageManagerException.from(e);
         } finally {
@@ -8570,66 +8622,25 @@
         }
 
         // Static shared libraries have synthetic package names
-        if (pkg.applicationInfo.isStaticSharedLibrary()) {
-            renameStaticSharedLibraryPackage(pkg);
+        if (parsedPackage.isStaticSharedLibrary()) {
+            renameStaticSharedLibraryPackage(parsedPackage);
         }
 
-        return scanPackageChildLI(pkg, parseFlags, scanFlags, currentTime, user);
-    }
-
-    /**
-     *  Scans a package and returns the newly parsed package.
-     *  @throws PackageManagerException on a parse error.
-     */
-    @GuardedBy({"mInstallLock", "mLock"})
-    private PackageParser.Package scanPackageChildLI(PackageParser.Package pkg,
-            final @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime,
-            @Nullable UserHandle user)
-                    throws PackageManagerException {
-        // If the package has children and this is the first dive in the function
-        // we scan the package with the SCAN_CHECK_ONLY flag set to see whether all
-        // packages (parent and children) would be successfully scanned before the
-        // actual scan since scanning mutates internal state and we want to atomically
-        // install the package and its children.
-        if ((scanFlags & SCAN_CHECK_ONLY) == 0) {
-            if (pkg.childPackages != null && pkg.childPackages.size() > 0) {
-                scanFlags |= SCAN_CHECK_ONLY;
-            }
-        } else {
-            scanFlags &= ~SCAN_CHECK_ONLY;
-        }
-
-        // Scan the parent
-        PackageParser.Package scannedPkg = addForInitLI(pkg, parseFlags,
-                scanFlags, currentTime, user);
-
-        // Scan the children
-        final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
-        for (int i = 0; i < childCount; i++) {
-            PackageParser.Package childPackage = pkg.childPackages.get(i);
-            addForInitLI(childPackage, parseFlags, scanFlags,
-                    currentTime, user);
-        }
-
-
-        if ((scanFlags & SCAN_CHECK_ONLY) != 0) {
-            return scanPackageChildLI(pkg, parseFlags, scanFlags, currentTime, user);
-        }
-
-        return scannedPkg;
+        return addForInitLI(parsedPackage, parseFlags, scanFlags, currentTime, user);
     }
 
     /**
      * Returns if forced apk verification can be skipped for the whole package, including splits.
      */
-    private boolean canSkipForcedPackageVerification(PackageParser.Package pkg) {
-        if (!canSkipForcedApkVerification(pkg.baseCodePath)) {
+    private boolean canSkipForcedPackageVerification(AndroidPackage pkg) {
+        if (!canSkipForcedApkVerification(pkg.getBaseCodePath())) {
             return false;
         }
         // TODO: Allow base and splits to be verified individually.
-        if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) {
-            for (int i = 0; i < pkg.splitCodePaths.length; i++) {
-                if (!canSkipForcedApkVerification(pkg.splitCodePaths[i])) {
+        String[] splitCodePaths = pkg.getSplitCodePaths();
+        if (!ArrayUtils.isEmpty(splitCodePaths)) {
+            for (int i = 0; i < splitCodePaths.length; i++) {
+                if (!canSkipForcedApkVerification(splitCodePaths[i])) {
                     return false;
                 }
             }
@@ -8678,7 +8689,7 @@
      * <p>NOTE: The return value should be removed. It's the passed in package object.
      */
     @GuardedBy({"mInstallLock", "mLock"})
-    private PackageParser.Package addForInitLI(PackageParser.Package pkg,
+    private AndroidPackage addForInitLI(ParsedPackage parsedPackage,
             @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime,
             @Nullable UserHandle user)
                     throws PackageManagerException {
@@ -8694,22 +8705,23 @@
         // stack [such as scanPackageOnly()]. However, we verify the application
         // info prior to that [in scanPackageNew()] and thus have to setup
         // the application info early.
-        pkg.setApplicationVolumeUuid(pkg.volumeUuid);
-        pkg.setApplicationInfoCodePath(pkg.codePath);
-        pkg.setApplicationInfoBaseCodePath(pkg.baseCodePath);
-        pkg.setApplicationInfoSplitCodePaths(pkg.splitCodePaths);
-        pkg.setApplicationInfoResourcePath(pkg.codePath);
-        pkg.setApplicationInfoBaseResourcePath(pkg.baseCodePath);
-        pkg.setApplicationInfoSplitResourcePaths(pkg.splitCodePaths);
+        // TODO(b/135203078): Remove all of these application info calls
+        parsedPackage.setApplicationVolumeUuid(parsedPackage.getVolumeUuid())
+                .setApplicationInfoCodePath(parsedPackage.getCodePath())
+                .setApplicationInfoResourcePath(parsedPackage.getCodePath())
+                .setApplicationInfoBaseResourcePath(parsedPackage.getBaseCodePath())
+                .setApplicationInfoSplitResourcePaths(parsedPackage.getSplitCodePaths());
 
         synchronized (mLock) {
-            renamedPkgName = mSettings.getRenamedPackageLPr(pkg.mRealPackage);
-            final String realPkgName = getRealPackageName(pkg, renamedPkgName);
+            renamedPkgName = mSettings.getRenamedPackageLPr(parsedPackage.getRealPackage());
+            final String realPkgName = getRealPackageName(parsedPackage, renamedPkgName);
             if (realPkgName != null) {
-                ensurePackageRenamed(pkg, renamedPkgName);
+                ensurePackageRenamed(parsedPackage, renamedPkgName);
             }
-            final PackageSetting originalPkgSetting = getOriginalPackageLocked(pkg, renamedPkgName);
-            final PackageSetting installedPkgSetting = mSettings.getPackageLPr(pkg.packageName);
+            final PackageSetting originalPkgSetting = getOriginalPackageLocked(parsedPackage,
+                    renamedPkgName);
+            final PackageSetting installedPkgSetting = mSettings.getPackageLPr(
+                    parsedPackage.getPackageName());
             pkgSetting = originalPkgSetting == null ? installedPkgSetting : originalPkgSetting;
             pkgAlreadyExists = pkgSetting != null;
             final String disabledPkgName = pkgAlreadyExists ? pkgSetting.name : pkg.packageName;
@@ -8730,49 +8742,29 @@
                 Slog.d(TAG, "updatedPkg = " + disabledPkgSetting);
             }
 
-            final SharedUserSetting sharedUserSetting = (pkg.mSharedUserId != null)
-                    ? mSettings.getSharedUserLPw(pkg.mSharedUserId,
+            final SharedUserSetting sharedUserSetting = (parsedPackage.getSharedUserId() != null)
+                    ? mSettings.getSharedUserLPw(parsedPackage.getSharedUserId(),
                             0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/, true)
                     : null;
             if (DEBUG_PACKAGE_SCANNING
                     && (parseFlags & PackageParser.PARSE_CHATTY) != 0
                     && sharedUserSetting != null) {
-                Log.d(TAG, "Shared UserID " + pkg.mSharedUserId
+                Log.d(TAG, "Shared UserID " + parsedPackage.getSharedUserId()
                         + " (uid=" + sharedUserSetting.userId + "):"
                         + " packages=" + sharedUserSetting.packages);
             }
 
             if (scanSystemPartition) {
-                // Potentially prune child packages. If the application on the /system
-                // partition has been updated via OTA, but, is still disabled by a
-                // version on /data, cycle through all of its children packages and
-                // remove children that are no longer defined.
                 if (isSystemPkgUpdated) {
-                    final int scannedChildCount = (pkg.childPackages != null)
-                            ? pkg.childPackages.size() : 0;
-                    final int disabledChildCount = disabledPkgSetting.childPackageNames != null
-                            ? disabledPkgSetting.childPackageNames.size() : 0;
-                    for (int i = 0; i < disabledChildCount; i++) {
-                        String disabledChildPackageName =
-                                disabledPkgSetting.childPackageNames.get(i);
-                        boolean disabledPackageAvailable = false;
-                        for (int j = 0; j < scannedChildCount; j++) {
-                            PackageParser.Package childPkg = pkg.childPackages.get(j);
-                            if (childPkg.packageName.equals(disabledChildPackageName)) {
-                                disabledPackageAvailable = true;
-                                break;
-                            }
-                        }
-                        if (!disabledPackageAvailable) {
-                            mSettings.removeDisabledSystemPackageLPw(disabledChildPackageName);
-                        }
-                    }
                     // we're updating the disabled package, so, scan it as the package setting
-                    final ScanRequest request = new ScanRequest(pkg, sharedUserSetting, null,
-                            disabledPkgSetting /* pkgSetting */, null /* disabledPkgSetting */,
-                            null /* originalPkgSetting */, null, parseFlags, scanFlags,
-                            (pkg == mPlatformPackage), user);
-                    applyPolicy(pkg, parseFlags, scanFlags, mPlatformPackage);
+                    boolean isPlatformPackage = mPlatformPackage != null
+                            && Objects.equals(mPlatformPackage.getPackageName(),
+                            parsedPackage.getPackageName());
+                    final ScanRequest request = new ScanRequest(parsedPackage, sharedUserSetting,
+                            null, disabledPkgSetting /* pkgSetting */,
+                            null /* disabledPkgSetting */, null /* originalPkgSetting */,
+                            null, parseFlags, scanFlags, isPlatformPackage, user);
+                    applyPolicy(parsedPackage, parseFlags, scanFlags, mPlatformPackage);
                     final ScanResult scanResult =
                             scanPackageOnlyLI(request, mInjector, mFactoryTest, -1L);
                     if (scanResult.existingSettingCopied && scanResult.request.pkgSetting != null) {
@@ -8783,9 +8775,9 @@
         }
 
         final boolean newPkgChangedPaths =
-                pkgAlreadyExists && !pkgSetting.codePathString.equals(pkg.codePath);
+                pkgAlreadyExists && !pkgSetting.codePathString.equals(parsedPackage.getCodePath());
         final boolean newPkgVersionGreater =
-                pkgAlreadyExists && pkg.getLongVersionCode() > pkgSetting.versionCode;
+                pkgAlreadyExists && parsedPackage.getLongVersionCode() > pkgSetting.versionCode;
         final boolean isSystemPkgBetter = scanSystemPartition && isSystemPkgUpdated
                 && newPkgChangedPaths && newPkgVersionGreater;
         if (isSystemPkgBetter) {
@@ -8801,12 +8793,13 @@
             logCriticalInfo(Log.WARN,
                     "System package updated;"
                     + " name: " + pkgSetting.name
-                    + "; " + pkgSetting.versionCode + " --> " + pkg.getLongVersionCode()
-                    + "; " + pkgSetting.codePathString + " --> " + pkg.codePath);
+                    + "; " + pkgSetting.versionCode + " --> " + parsedPackage.getLongVersionCode()
+                    + "; " + pkgSetting.codePathString + " --> " + parsedPackage.getCodePath());
 
             final InstallArgs args = createInstallArgsForExisting(
                     pkgSetting.codePathString,
-                    pkgSetting.resourcePathString, getAppDexInstructionSets(pkgSetting));
+                    pkgSetting.resourcePathString, getAppDexInstructionSets(
+                            pkgSetting.primaryCpuAbiString, pkgSetting.secondaryCpuAbiString));
             args.cleanUpResourcesLI();
             synchronized (mLock) {
                 mSettings.enableSystemPackageLPw(pkgSetting.name);
@@ -8817,9 +8810,10 @@
             // The version of the application on the /system partition is less than or
             // equal to the version on the /data partition. Throw an exception and use
             // the application already installed on the /data partition.
-            throw new PackageManagerException(Log.WARN, "Package " + pkg.packageName + " at "
-                    + pkg.codePath + " ignored: updated version " + pkgSetting.versionCode
-                    + " better than this " + pkg.getLongVersionCode());
+            throw new PackageManagerException(Log.WARN, "Package " + parsedPackage.getPackageName()
+                    + " at " + parsedPackage.getCodePath() + " ignored: updated version "
+                    + pkgSetting.versionCode + " better than this "
+                    + parsedPackage.getLongVersionCode());
         }
 
         // Verify certificates against what was last scanned. Force re-collecting certificate in two
@@ -8830,7 +8824,7 @@
         final boolean forceCollect = scanSystemPartition ? mIsUpgrade
                 : PackageManagerServiceUtils.isApkVerificationForced(pkgSetting);
         if (DEBUG_VERIFY && forceCollect) {
-            Slog.d(TAG, "Force collect certificate of " + pkg.packageName);
+            Slog.d(TAG, "Force collect certificate of " + parsedPackage.getPackageName());
         }
 
         // Full APK verification can be skipped during certificate collection, only if the file is
@@ -8838,11 +8832,11 @@
         // cases, only data in Signing Block is verified instead of the whole file.
         // TODO(b/136132412): skip for Incremental installation
         final boolean skipVerify = scanSystemPartition
-                || (forceCollect && canSkipForcedPackageVerification(pkg));
-        collectCertificatesLI(pkgSetting, pkg, forceCollect, skipVerify);
+                || (forceCollect && canSkipForcedPackageVerification(parsedPackage));
+        collectCertificatesLI(pkgSetting, parsedPackage, forceCollect, skipVerify);
 
         // Reset profile if the application version is changed
-        maybeClearProfilesForUpgradesLI(pkgSetting, pkg);
+        maybeClearProfilesForUpgradesLI(pkgSetting, parsedPackage);
 
         /*
          * A new system app appeared, but we already had a non-system one of the
@@ -8854,17 +8848,20 @@
         if (scanSystemPartition && !isSystemPkgUpdated && pkgAlreadyExists
                 && !pkgSetting.isSystem()) {
 
-            if (!pkg.mSigningDetails.checkCapability(pkgSetting.signatures.mSigningDetails,
+            if (!parsedPackage.getSigningDetails()
+                    .checkCapability(pkgSetting.signatures.mSigningDetails,
                     PackageParser.SigningDetails.CertCapabilities.INSTALLED_DATA)
                             && !pkgSetting.signatures.mSigningDetails.checkCapability(
-                                    pkg.mSigningDetails,
+                                    parsedPackage.getSigningDetails(),
                                     PackageParser.SigningDetails.CertCapabilities.ROLLBACK)) {
                 logCriticalInfo(Log.WARN,
                         "System package signature mismatch;"
                         + " name: " + pkgSetting.name);
-                try (PackageFreezer freezer = freezePackage(pkg.packageName,
+                try (@SuppressWarnings("unused") PackageFreezer freezer = freezePackage(
+                        parsedPackage.getPackageName(),
                         "scanPackageInternalLI")) {
-                    deletePackageLIF(pkg.packageName, null, true, null, 0, null, false, null);
+                    deletePackageLIF(parsedPackage.getPackageName(), null, true, null, 0, null,
+                            false, null);
                 }
                 pkgSetting = null;
             } else if (newPkgVersionGreater) {
@@ -8873,12 +8870,15 @@
                 // and replace it with the version on /system.
                 logCriticalInfo(Log.WARN,
                         "System package enabled;"
-                        + " name: " + pkgSetting.name
-                        + "; " + pkgSetting.versionCode + " --> " + pkg.getLongVersionCode()
-                        + "; " + pkgSetting.codePathString + " --> " + pkg.codePath);
+                                + " name: " + pkgSetting.name
+                                + "; " + pkgSetting.versionCode + " --> "
+                                + parsedPackage.getLongVersionCode()
+                                + "; " + pkgSetting.codePathString + " --> "
+                                + parsedPackage.getCodePath());
                 InstallArgs args = createInstallArgsForExisting(
                         pkgSetting.codePathString,
-                        pkgSetting.resourcePathString, getAppDexInstructionSets(pkgSetting));
+                        pkgSetting.resourcePathString, getAppDexInstructionSets(
+                                pkgSetting.primaryCpuAbiString, pkgSetting.secondaryCpuAbiString));
                 synchronized (mInstallLock) {
                     args.cleanUpResourcesLI();
                 }
@@ -8889,13 +8889,15 @@
                 shouldHideSystemApp = true;
                 logCriticalInfo(Log.INFO,
                         "System package disabled;"
-                        + " name: " + pkgSetting.name
-                        + "; old: " + pkgSetting.codePathString + " @ " + pkgSetting.versionCode
-                        + "; new: " + pkg.codePath + " @ " + pkg.codePath);
+                                + " name: " + pkgSetting.name
+                                + "; old: " + pkgSetting.codePathString + " @ "
+                                + pkgSetting.versionCode
+                                + "; new: " + parsedPackage.getCodePath() + " @ "
+                                + parsedPackage.getCodePath());
             }
         }
 
-        final ScanResult scanResult = scanPackageNewLI(pkg, parseFlags, scanFlags
+        final ScanResult scanResult = scanPackageNewLI(parsedPackage, parseFlags, scanFlags
                 | SCAN_UPDATE_SIGNATURE, currentTime, user);
         if (scanResult.success) {
             synchronized (mLock) {
@@ -8908,7 +8910,7 @@
                                     mSharedLibraries,
                                     mPackages,
                                     Collections.singletonMap(
-                                            pkgName, getSettingsVersionForPackage(pkg)),
+                                            pkgName, getSettingsVersionForPackage(parsedPackage)),
                                     Collections.singletonMap(pkgName,
                                             getSharedLibLatestVersionSetting(scanResult))),
                             mSettings.mKeySetManagerService);
@@ -8925,16 +8927,17 @@
 
         if (shouldHideSystemApp) {
             synchronized (mLock) {
-                mSettings.disableSystemPackageLPw(pkg.packageName, true);
+                mSettings.disableSystemPackageLPw(parsedPackage.getPackageName(), true);
             }
         }
         return scanResult.pkgSetting.pkg;
     }
 
-    private static void renameStaticSharedLibraryPackage(PackageParser.Package pkg) {
+    // TODO:(b/135203078): Move to parsing
+    private static void renameStaticSharedLibraryPackage(ParsedPackage parsedPackage) {
         // Derive the new package synthetic package name
-        pkg.setPackageName(pkg.packageName + STATIC_SHARED_LIB_DELIMITER
-                + pkg.staticSharedLibVersion);
+        parsedPackage.setPackageName(parsedPackage.getPackageName() + STATIC_SHARED_LIB_DELIMITER
+                + parsedPackage.getStaticSharedLibVersion());
     }
 
     static String fixProcessName(String defProcessName, String processName) {
@@ -9035,7 +9038,7 @@
             return;
         }
 
-        List<PackageParser.Package> pkgs;
+        List<AndroidPackage> pkgs;
         synchronized (mLock) {
             pkgs = PackageManagerServiceUtils.getPackagesForDexopt(mPackages.values(), this);
         }
@@ -9058,8 +9061,8 @@
     /*
      * Return the prebuilt profile path given a package base code path.
      */
-    private static String getPrebuildProfilePath(PackageParser.Package pkg) {
-        return pkg.baseCodePath + ".prof";
+    private static String getPrebuildProfilePath(AndroidPackage pkg) {
+        return pkg.getBaseCodePath() + ".prof";
     }
 
     /**
@@ -9068,7 +9071,7 @@
      * which are (in order) {@code numberOfPackagesOptimized}, {@code numberOfPackagesSkipped}
      * and {@code numberOfPackagesFailed}.
      */
-    private int[] performDexOptUpgrade(List<PackageParser.Package> pkgs, boolean showDialog,
+    private int[] performDexOptUpgrade(List<AndroidPackage> pkgs, boolean showDialog,
             final int compilationReason, boolean bootComplete) {
 
         int numberOfPackagesVisited = 0;
@@ -9077,7 +9080,7 @@
         int numberOfPackagesFailed = 0;
         final int numberOfPackagesToDexopt = pkgs.size();
 
-        for (PackageParser.Package pkg : pkgs) {
+        for (AndroidPackage pkg : pkgs) {
             numberOfPackagesVisited++;
 
             boolean useProfileForDexopt = false;
@@ -9093,7 +9096,7 @@
                         // PackageDexOptimizer to prevent this happening on first boot. The issue
                         // is that we don't have a good way to say "do this only once".
                         if (!mInstaller.copySystemProfile(profileFile.getAbsolutePath(),
-                                pkg.applicationInfo.uid, pkg.packageName,
+                                pkg.getUid(), pkg.getPackageName(),
                                 ArtManager.getProfileName(null))) {
                             Log.e(TAG, "Installer failed to copy system profile!");
                         } else {
@@ -9106,11 +9109,12 @@
                                 e);
                     }
                 } else {
-                    PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(pkg.packageName);
+                    PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(
+                            pkg.getPackageName());
                     // Handle compressed APKs in this path. Only do this for stubs with profiles to
                     // minimize the number off apps being speed-profile compiled during first boot.
                     // The other paths will not change the filter.
-                    if (disabledPs != null && disabledPs.pkg.isStub) {
+                    if (disabledPs != null && disabledPs.pkg.isStub()) {
                         // The package is the stub one, remove the stub suffix to get the normal
                         // package and APK names.
                         String systemProfilePath =
@@ -9129,7 +9133,7 @@
                                 // issue is that we don't have a good way to say "do this only
                                 // once".
                                 if (!mInstaller.copySystemProfile(profileFile.getAbsolutePath(),
-                                        pkg.applicationInfo.uid, pkg.packageName,
+                                        pkg.getUid(), pkg.getPackageName(),
                                         ArtManager.getProfileName(null))) {
                                     Log.e(TAG, "Failed to copy system profile for stub package!");
                                 } else {
@@ -9146,7 +9150,7 @@
 
             if (!PackageDexOptimizer.canOptimizePackage(pkg)) {
                 if (DEBUG_DEXOPT) {
-                    Log.i(TAG, "Skipping update of of non-optimizable app " + pkg.packageName);
+                    Log.i(TAG, "Skipping update of non-optimizable app " + pkg.getPackageName());
                 }
                 numberOfPackagesSkipped++;
                 continue;
@@ -9154,7 +9158,7 @@
 
             if (DEBUG_DEXOPT) {
                 Log.i(TAG, "Updating app " + numberOfPackagesVisited + " of " +
-                        numberOfPackagesToDexopt + ": " + pkg.packageName);
+                        numberOfPackagesToDexopt + ": " + pkg.getPackageName());
             }
 
             if (showDialog) {
@@ -9191,7 +9195,7 @@
                 dexoptFlags |= DexoptOptions.DEXOPT_INSTALL_WITH_DEX_METADATA_FILE;
             }
             int primaryDexOptStaus = performDexOptTraced(new DexoptOptions(
-                    pkg.packageName,
+                    pkg.getPackageName(),
                     pkgCompilationReason,
                     dexoptFlags));
 
@@ -9235,11 +9239,11 @@
 
     @GuardedBy("mLock")
     private void notifyPackageUseLocked(String packageName, int reason) {
-        final PackageParser.Package p = mPackages.get(packageName);
+        final AndroidPackage p = mPackages.get(packageName);
         if (p == null) {
             return;
         }
-        p.mLastPackageUsageTimeInMills[reason] = System.currentTimeMillis();
+        p.mutate().setLastPackageUsageTimeInMills(reason, System.currentTimeMillis());
     }
 
     @Override
@@ -9319,7 +9323,7 @@
     */
     @Override
     public boolean compileLayouts(String packageName) {
-        PackageParser.Package pkg;
+        AndroidPackage pkg;
         synchronized (mLock) {
             pkg = mPackages.get(packageName);
             if (pkg == null) {
@@ -9366,7 +9370,7 @@
     // Run dexopt on a given package. Returns true if dexopt did not fail, i.e.
     // if the package can now be considered up to date for the given filter.
     private int performDexOptInternal(DexoptOptions options) {
-        PackageParser.Package p;
+        AndroidPackage p;
         synchronized (mLock) {
             p = mPackages.get(options.getPackageName());
             if (p == null) {
@@ -9389,16 +9393,16 @@
     public ArraySet<String> getOptimizablePackages() {
         ArraySet<String> pkgs = new ArraySet<>();
         synchronized (mLock) {
-            for (PackageParser.Package p : mPackages.values()) {
+            for (AndroidPackage p : mPackages.values()) {
                 if (PackageDexOptimizer.canOptimizePackage(p)) {
-                    pkgs.add(p.packageName);
+                    pkgs.add(p.getPackageName());
                 }
             }
         }
         return pkgs;
     }
 
-    private int performDexOptInternalWithDependenciesLI(PackageParser.Package p,
+    private int performDexOptInternalWithDependenciesLI(AndroidPackage p,
             DexoptOptions options) {
         // Select the dex optimizer based on the force parameter.
         // Note: The force option is rarely used (cmdline input for testing, mostly), so it's OK to
@@ -9415,14 +9419,15 @@
         // and the first package that uses the library will dexopt it. The
         // others will see that the compiled code for the library is up to date.
         Collection<SharedLibraryInfo> deps = findSharedLibraries(p);
-        final String[] instructionSets = getAppDexInstructionSets(p.applicationInfo);
+        final String[] instructionSets = getAppDexInstructionSets(p.getPrimaryCpuAbi(),
+                p.getSecondaryCpuAbi());
         if (!deps.isEmpty()) {
             DexoptOptions libraryOptions = new DexoptOptions(options.getPackageName(),
                     options.getCompilationReason(), options.getCompilerFilter(),
                     options.getSplitName(),
                     options.getFlags() | DexoptOptions.DEXOPT_AS_SHARED_LIBRARY);
             for (SharedLibraryInfo info : deps) {
-                PackageParser.Package depPackage = null;
+                AndroidPackage depPackage = null;
                 synchronized (mLock) {
                     depPackage = mPackages.get(info.getPackageName());
                 }
@@ -9430,7 +9435,7 @@
                     // TODO: Analyze and investigate if we (should) profile libraries.
                     pdo.performDexOpt(depPackage, instructionSets,
                             getOrCreateCompilerPackageStats(depPackage),
-                            mDexManager.getPackageUseInfoOrDefault(depPackage.packageName),
+                            mDexManager.getPackageUseInfoOrDefault(depPackage.getPackageName()),
                             libraryOptions);
                 } else {
                     // TODO(ngeoffray): Support dexopting system shared libraries.
@@ -9439,7 +9444,7 @@
         }
         return pdo.performDexOpt(p, instructionSets,
                 getOrCreateCompilerPackageStats(p),
-                mDexManager.getPackageUseInfoOrDefault(p.packageName), options);
+                mDexManager.getPackageUseInfoOrDefault(p.getPackageName()), options);
     }
 
     /**
@@ -9480,11 +9485,11 @@
         }
     }
 
-    private static List<SharedLibraryInfo> findSharedLibraries(PackageParser.Package p) {
-        if (p.usesLibraryInfos != null) {
+    private static List<SharedLibraryInfo> findSharedLibraries(AndroidPackage p) {
+        if (p.getUsesLibraryInfos() != null) {
             ArrayList<SharedLibraryInfo> retValue = new ArrayList<>();
             Set<String> collectedNames = new HashSet<>();
-            for (SharedLibraryInfo info : p.usesLibraryInfos) {
+            for (SharedLibraryInfo info : p.getUsesLibraryInfos()) {
                 findSharedLibrariesRecursive(info, retValue, collectedNames);
             }
             return retValue;
@@ -9507,13 +9512,13 @@
         }
     }
 
-    List<PackageParser.Package> findSharedNonSystemLibraries(PackageParser.Package pkg) {
+    List<AndroidPackage> findSharedNonSystemLibraries(AndroidPackage pkg) {
         List<SharedLibraryInfo> deps = findSharedLibraries(pkg);
         if (!deps.isEmpty()) {
-            ArrayList<PackageParser.Package> retValue = new ArrayList<>();
+            ArrayList<AndroidPackage> retValue = new ArrayList<>();
             synchronized (mLock) {
                 for (SharedLibraryInfo info : deps) {
-                    PackageParser.Package depPackage = mPackages.get(info.getPackageName());
+                    AndroidPackage depPackage = mPackages.get(info.getPackageName());
                     if (depPackage != null) {
                         retValue.add(depPackage);
                     }
@@ -9551,9 +9556,9 @@
         return versionedLib.get(version);
     }
 
-    private SharedLibraryInfo getLatestSharedLibraVersionLPr(PackageParser.Package pkg) {
+    private SharedLibraryInfo getLatestSharedLibraVersionLPr(AndroidPackage pkg) {
         LongSparseArray<SharedLibraryInfo> versionedLib = mSharedLibraries.get(
-                pkg.staticSharedLibName);
+                pkg.getStaticSharedLibName());
         if (versionedLib == null) {
             return null;
         }
@@ -9561,7 +9566,7 @@
         final int versionCount = versionedLib.size();
         for (int i = 0; i < versionCount; i++) {
             final long libVersion = versionedLib.keyAt(i);
-            if (libVersion < pkg.staticSharedLibVersion) {
+            if (libVersion < pkg.getStaticSharedLibVersion()) {
                 previousLibVersion = Math.max(previousLibVersion, libVersion);
             }
         }
@@ -9577,7 +9582,7 @@
         PackageSetting sharedLibPackage = null;
         synchronized (mLock) {
             final SharedLibraryInfo latestSharedLibraVersionLPr =
-                    getLatestSharedLibraVersionLPr(scanResult.pkgSetting.pkg);
+                    getLatestSharedLibraVersionLPr(scanResult.request.parsedPackage);
             if (latestSharedLibraVersionLPr != null) {
                 sharedLibPackage = mSettings.getPackageLPr(
                         latestSharedLibraVersionLPr.getPackageName());
@@ -9606,7 +9611,7 @@
 
     @Override
     public void dumpProfiles(String packageName) {
-        PackageParser.Package pkg;
+        AndroidPackage pkg;
         synchronized (mLock) {
             pkg = mPackages.get(packageName);
             if (pkg == null) {
@@ -9617,7 +9622,7 @@
         int callingUid = Binder.getCallingUid();
         if (callingUid != Process.SHELL_UID &&
             callingUid != Process.ROOT_UID &&
-            callingUid != pkg.applicationInfo.uid) {
+            callingUid != pkg.getUid()) {
             throw new SecurityException("dumpProfiles");
         }
 
@@ -9632,7 +9637,7 @@
     public void forceDexOpt(String packageName) {
         enforceSystemOrRoot("forceDexOpt");
 
-        PackageParser.Package pkg;
+        AndroidPackage pkg;
         synchronized (mLock) {
             pkg = mPackages.get(packageName);
             if (pkg == null) {
@@ -9659,15 +9664,15 @@
     }
 
     @GuardedBy("mLock")
-    private boolean verifyPackageUpdateLPr(PackageSetting oldPkg, PackageParser.Package newPkg) {
+    private boolean verifyPackageUpdateLPr(PackageSetting oldPkg, AndroidPackage newPkg) {
         if ((oldPkg.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) {
             Slog.w(TAG, "Unable to update from " + oldPkg.name
-                    + " to " + newPkg.packageName
+                    + " to " + newPkg.getPackageName()
                     + ": old package not in system partition");
             return false;
         } else if (mPackages.get(oldPkg.name) != null) {
             Slog.w(TAG, "Unable to update from " + oldPkg.name
-                    + " to " + newPkg.packageName
+                    + " to " + newPkg.getPackageName()
                     + ": old package still exists");
             return false;
         }
@@ -9691,122 +9696,86 @@
         return (userId == UserHandle.USER_ALL) ? mUserManager.getUserIds() : new int[] { userId };
     }
 
-    private void clearAppDataLIF(PackageParser.Package pkg, int userId, int flags) {
+    private void clearAppDataLIF(AndroidPackage pkg, int userId, int flags) {
         if (pkg == null) {
             Slog.wtf(TAG, "Package was null!", new Throwable());
             return;
         }
         clearAppDataLeafLIF(pkg, userId, flags);
-        final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
-        for (int i = 0; i < childCount; i++) {
-            clearAppDataLeafLIF(pkg.childPackages.get(i), userId, flags);
-        }
 
         if ((flags & Installer.FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES) == 0) {
             clearAppProfilesLIF(pkg, UserHandle.USER_ALL);
         }
     }
 
-    private void clearAppDataLeafLIF(PackageParser.Package pkg, int userId, int flags) {
+    private void clearAppDataLeafLIF(AndroidPackage pkg, int userId, int flags) {
         final PackageSetting ps;
         synchronized (mLock) {
-            ps = mSettings.mPackages.get(pkg.packageName);
+            ps = mSettings.mPackages.get(pkg.getPackageName());
         }
         for (int realUserId : resolveUserIds(userId)) {
             final long ceDataInode = (ps != null) ? ps.getCeDataInode(realUserId) : 0;
             try {
-                mInstaller.clearAppData(pkg.volumeUuid, pkg.packageName, realUserId, flags,
-                        ceDataInode);
+                mInstaller.clearAppData(pkg.getVolumeUuid(), pkg.getPackageName(), realUserId,
+                        flags, ceDataInode);
             } catch (InstallerException e) {
                 Slog.w(TAG, String.valueOf(e));
             }
         }
     }
 
-    private void destroyAppDataLIF(PackageParser.Package pkg, int userId, int flags) {
+    private void destroyAppDataLIF(AndroidPackage pkg, int userId, int flags) {
         if (pkg == null) {
             Slog.wtf(TAG, "Package was null!", new Throwable());
             return;
         }
         destroyAppDataLeafLIF(pkg, userId, flags);
-        final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
-        for (int i = 0; i < childCount; i++) {
-            destroyAppDataLeafLIF(pkg.childPackages.get(i), userId, flags);
-        }
     }
 
-    private void destroyAppDataLeafLIF(PackageParser.Package pkg, int userId, int flags) {
+    private void destroyAppDataLeafLIF(AndroidPackage pkg, int userId, int flags) {
         final PackageSetting ps;
         synchronized (mLock) {
-            ps = mSettings.mPackages.get(pkg.packageName);
+            ps = mSettings.mPackages.get(pkg.getPackageName());
         }
         for (int realUserId : resolveUserIds(userId)) {
             final long ceDataInode = (ps != null) ? ps.getCeDataInode(realUserId) : 0;
             try {
-                mInstaller.destroyAppData(pkg.volumeUuid, pkg.packageName, realUserId, flags,
-                        ceDataInode);
+                mInstaller.destroyAppData(pkg.getVolumeUuid(), pkg.getPackageName(), realUserId,
+                        flags, ceDataInode);
             } catch (InstallerException e) {
                 Slog.w(TAG, String.valueOf(e));
             }
-            mDexManager.notifyPackageDataDestroyed(pkg.packageName, userId);
+            mDexManager.notifyPackageDataDestroyed(pkg.getPackageName(), userId);
         }
     }
 
-    private void destroyAppProfilesLIF(PackageParser.Package pkg) {
+    private void destroyAppProfilesLIF(AndroidPackage pkg) {
         if (pkg == null) {
             Slog.wtf(TAG, "Package was null!", new Throwable());
             return;
         }
         destroyAppProfilesLeafLIF(pkg);
-        final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
-        for (int i = 0; i < childCount; i++) {
-            destroyAppProfilesLeafLIF(pkg.childPackages.get(i));
-        }
     }
 
-    private void destroyAppProfilesLeafLIF(PackageParser.Package pkg) {
+    private void destroyAppProfilesLeafLIF(AndroidPackage pkg) {
         try {
-            mInstaller.destroyAppProfiles(pkg.packageName);
+            mInstaller.destroyAppProfiles(pkg.getPackageName());
         } catch (InstallerException e) {
             Slog.w(TAG, String.valueOf(e));
         }
     }
 
-    private void clearAppProfilesLIF(PackageParser.Package pkg, int userId) {
+    private void clearAppProfilesLIF(AndroidPackage pkg, int userId) {
         if (pkg == null) {
             Slog.wtf(TAG, "Package was null!", new Throwable());
             return;
         }
         mArtManagerService.clearAppProfiles(pkg);
-        final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
-        for (int i = 0; i < childCount; i++) {
-            mArtManagerService.clearAppProfiles(pkg.childPackages.get(i));
-        }
-    }
-
-    private void setInstallAndUpdateTime(PackageParser.Package pkg, long firstInstallTime,
-            long lastUpdateTime) {
-        // Set parent install/update time
-        PackageSetting ps = (PackageSetting) pkg.mExtras;
-        if (ps != null) {
-            ps.firstInstallTime = firstInstallTime;
-            ps.lastUpdateTime = lastUpdateTime;
-        }
-        // Set children install/update time
-        final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
-        for (int i = 0; i < childCount; i++) {
-            PackageParser.Package childPkg = pkg.childPackages.get(i);
-            ps = (PackageSetting) childPkg.mExtras;
-            if (ps != null) {
-                ps.firstInstallTime = firstInstallTime;
-                ps.lastUpdateTime = lastUpdateTime;
-            }
-        }
     }
 
     @GuardedBy("mLock")
     private void applyDefiningSharedLibraryUpdateLocked(
-            PackageParser.Package pkg, SharedLibraryInfo libInfo,
+            AndroidPackage pkg, SharedLibraryInfo libInfo,
             BiConsumer<SharedLibraryInfo, SharedLibraryInfo> action) {
         // Note that libraries defined by this package may be null if:
         // - Package manager was unable to create the shared library. The package still
@@ -9815,14 +9784,14 @@
         // - Package manager is in a state where package isn't scanned yet. This will
         //   get called again after scanning to fix the dependencies.
         if (pkg.isLibrary()) {
-            if (pkg.staticSharedLibName != null) {
+            if (pkg.getStaticSharedLibName() != null) {
                 SharedLibraryInfo definedLibrary = getSharedLibraryInfoLPr(
-                        pkg.staticSharedLibName, pkg.staticSharedLibVersion);
+                        pkg.getStaticSharedLibName(), pkg.getStaticSharedLibVersion());
                 if (definedLibrary != null) {
                     action.accept(definedLibrary, libInfo);
                 }
             } else {
-                for (String libraryName : pkg.libraryNames) {
+                for (String libraryName : pkg.getLibraryNames()) {
                     SharedLibraryInfo definedLibrary = getSharedLibraryInfoLPr(
                             libraryName, SharedLibraryInfo.VERSION_UNDEFINED);
                     if (definedLibrary != null) {
@@ -9834,19 +9803,19 @@
     }
 
     @GuardedBy("mLock")
-    private void addSharedLibraryLPr(PackageParser.Package pkg, Set<String> usesLibraryFiles,
-            SharedLibraryInfo libInfo, PackageParser.Package changingLib) {
+    private void addSharedLibraryLPr(AndroidPackage pkg, Set<String> usesLibraryFiles,
+            SharedLibraryInfo libInfo, AndroidPackage changingLib) {
         if (libInfo.getPath() != null) {
             usesLibraryFiles.add(libInfo.getPath());
             return;
         }
-        PackageParser.Package p = mPackages.get(libInfo.getPackageName());
-        if (changingLib != null && changingLib.packageName.equals(libInfo.getPackageName())) {
+        AndroidPackage p = mPackages.get(libInfo.getPackageName());
+        if (changingLib != null && changingLib.getPackageName().equals(libInfo.getPackageName())) {
             // If we are doing this while in the middle of updating a library apk,
             // then we need to make sure to use that new apk for determining the
             // dependencies here.  (We haven't yet finished committing the new apk
             // to the package manager state.)
-            if (p == null || p.packageName.equals(changingLib.packageName)) {
+            if (p == null || p.getPackageName().equals(changingLib.getPackageName())) {
                 p = changingLib;
             }
         }
@@ -9856,23 +9825,23 @@
             applyDefiningSharedLibraryUpdateLocked(pkg, libInfo, (definingLibrary, dependency) -> {
                 definingLibrary.addDependency(dependency);
             });
-            if (p.usesLibraryFiles != null) {
-                Collections.addAll(usesLibraryFiles, p.usesLibraryFiles);
+            if (p.getUsesLibraryFiles() != null) {
+                Collections.addAll(usesLibraryFiles, p.getUsesLibraryFiles());
             }
         }
     }
 
     @GuardedBy("mLock")
-    private void updateSharedLibrariesLocked(PackageParser.Package pkg,
-            PackageParser.Package changingLib, Map<String, PackageParser.Package> availablePackages)
+    private void updateSharedLibrariesLocked(AndroidPackage pkg,
+            AndroidPackage changingLib, Map<String, AndroidPackage> availablePackages)
                     throws PackageManagerException {
         final ArrayList<SharedLibraryInfo> sharedLibraryInfos =
                 collectSharedLibraryInfos(pkg, availablePackages, mSharedLibraries, null);
         executeSharedLibrariesUpdateLPr(pkg, changingLib, sharedLibraryInfos);
     }
 
-    private static ArrayList<SharedLibraryInfo> collectSharedLibraryInfos(PackageParser.Package pkg,
-            Map<String, PackageParser.Package> availablePackages,
+    private static ArrayList<SharedLibraryInfo> collectSharedLibraryInfos(AndroidPackage pkg,
+            Map<String, AndroidPackage> availablePackages,
             @NonNull final Map<String, LongSparseArray<SharedLibraryInfo>> existingLibraries,
             @Nullable final Map<String, LongSparseArray<SharedLibraryInfo>> newLibraries)
             throws PackageManagerException {
@@ -9883,44 +9852,45 @@
         // that libraries are searched in the correct order) and must have no
         // duplicates.
         ArrayList<SharedLibraryInfo> usesLibraryInfos = null;
-        if (pkg.usesLibraries != null) {
-            usesLibraryInfos = collectSharedLibraryInfos(pkg.usesLibraries, null, null,
-                    pkg.packageName, true, pkg.applicationInfo.targetSdkVersion, null,
+        if (pkg.getUsesLibraries() != null) {
+            usesLibraryInfos = collectSharedLibraryInfos(pkg.getUsesLibraries(), null, null,
+                    pkg.getPackageName(), true, pkg.getTargetSdkVersion(), null,
                     availablePackages, existingLibraries, newLibraries);
         }
-        if (pkg.usesStaticLibraries != null) {
-            usesLibraryInfos = collectSharedLibraryInfos(pkg.usesStaticLibraries,
-                    pkg.usesStaticLibrariesVersions, pkg.usesStaticLibrariesCertDigests,
-                    pkg.packageName, true, pkg.applicationInfo.targetSdkVersion, usesLibraryInfos,
+        if (pkg.getUsesStaticLibraries() != null) {
+            usesLibraryInfos = collectSharedLibraryInfos(pkg.getUsesStaticLibraries(),
+                    pkg.getUsesStaticLibrariesVersions(), pkg.getUsesStaticLibrariesCertDigests(),
+                    pkg.getPackageName(), true, pkg.getTargetSdkVersion(), usesLibraryInfos,
                     availablePackages, existingLibraries, newLibraries);
         }
-        if (pkg.usesOptionalLibraries != null) {
-            usesLibraryInfos = collectSharedLibraryInfos(pkg.usesOptionalLibraries,
-                    null, null, pkg.packageName, false, pkg.applicationInfo.targetSdkVersion,
+        if (pkg.getUsesOptionalLibraries() != null) {
+            usesLibraryInfos = collectSharedLibraryInfos(pkg.getUsesOptionalLibraries(),
+                    null, null, pkg.getPackageName(), false, pkg.getTargetSdkVersion(),
                     usesLibraryInfos, availablePackages, existingLibraries, newLibraries);
         }
         return usesLibraryInfos;
     }
 
-    private void executeSharedLibrariesUpdateLPr(PackageParser.Package pkg,
-            PackageParser.Package changingLib, ArrayList<SharedLibraryInfo> usesLibraryInfos) {
+    private void executeSharedLibrariesUpdateLPr(AndroidPackage pkg,
+            AndroidPackage changingLib, ArrayList<SharedLibraryInfo> usesLibraryInfos) {
         // If the package provides libraries, clear their old dependencies.
         // This method will set them up again.
         applyDefiningSharedLibraryUpdateLocked(pkg, null, (definingLibrary, dependency) -> {
             definingLibrary.clearDependencies();
         });
         if (usesLibraryInfos != null) {
-            pkg.usesLibraryInfos = usesLibraryInfos;
+            pkg.mutate().setUsesLibraryInfos(usesLibraryInfos);
             // Use LinkedHashSet to preserve the order of files added to
             // usesLibraryFiles while eliminating duplicates.
             Set<String> usesLibraryFiles = new LinkedHashSet<>();
             for (SharedLibraryInfo libInfo : usesLibraryInfos) {
                 addSharedLibraryLPr(pkg, usesLibraryFiles, libInfo, changingLib);
             }
-            pkg.usesLibraryFiles = usesLibraryFiles.toArray(new String[usesLibraryFiles.size()]);
+            pkg.mutate().setUsesLibraryFiles(usesLibraryFiles.toArray(
+                    new String[usesLibraryFiles.size()]));
         } else {
-            pkg.usesLibraryInfos = null;
-            pkg.usesLibraryFiles = null;
+            pkg.mutate().setUsesLibraryInfos(null)
+                    .setUsesLibraryFiles(null);
         }
     }
 
@@ -9930,7 +9900,7 @@
             @Nullable long[] requiredVersions, @Nullable String[][] requiredCertDigests,
             @NonNull String packageName, boolean required, int targetSdk,
             @Nullable ArrayList<SharedLibraryInfo> outUsedLibraries,
-            @NonNull final Map<String, PackageParser.Package> availablePackages,
+            @NonNull final Map<String, AndroidPackage> availablePackages,
             @NonNull final Map<String, LongSparseArray<SharedLibraryInfo>> existingLibraries,
             @Nullable final Map<String, LongSparseArray<SharedLibraryInfo>> newLibraries)
             throws PackageManagerException {
@@ -9959,8 +9929,8 @@
                                     + " library " + libName + " version "
                                     + libraryInfo.getLongVersion() + "; failing!");
                     }
-                    PackageParser.Package libPkg =
-                            availablePackages.get(libraryInfo.getPackageName());
+                    AndroidPackage pkg = availablePackages.get(libraryInfo.getPackageName());
+                    SigningDetails libPkg = pkg == null ? null : pkg.getSigningDetails();
                     if (libPkg == null) {
                         throw new PackageManagerException(INSTALL_FAILED_MISSING_SHARED_LIBRARY,
                                 "Package " + packageName + " requires unavailable static shared"
@@ -9971,9 +9941,9 @@
                         // For apps targeting O MR1 we require explicit enumeration of all certs.
                         final String[] libCertDigests = (targetSdk >= Build.VERSION_CODES.O_MR1)
                                 ? PackageUtils.computeSignaturesSha256Digests(
-                                libPkg.mSigningDetails.signatures)
+                                libPkg.signatures)
                                 : PackageUtils.computeSignaturesSha256Digests(
-                                        new Signature[]{libPkg.mSigningDetails.signatures[0]});
+                                        new Signature[]{libPkg.signatures[0]});
 
                         // Take a shortcut if sizes don't match. Note that if an app doesn't
                         // target O we don't parse the "additional-certificate" tags similarly
@@ -10003,7 +9973,7 @@
                         // if the new one has been blessed by the old
                         byte[] digestBytes = HexEncoding.decode(
                                 expectedCertDigests[0], false /* allowSingleChar */);
-                        if (!libPkg.mSigningDetails.hasSha256Certificate(digestBytes)) {
+                        if (!libPkg.hasSha256Certificate(digestBytes)) {
                             throw new PackageManagerException(
                                     INSTALL_FAILED_MISSING_SHARED_LIBRARY,
                                     "Package " + packageName + " requires differently signed" +
@@ -10035,28 +10005,28 @@
     }
 
     @GuardedBy("mLock")
-    private ArrayList<PackageParser.Package> updateAllSharedLibrariesLocked(
-            PackageParser.Package updatedPkg,
-            Map<String, PackageParser.Package> availablePackages) {
-        ArrayList<PackageParser.Package> resultList = null;
+    private ArrayList<AndroidPackage> updateAllSharedLibrariesLocked(
+            AndroidPackage updatedPkg,
+            Map<String, AndroidPackage> availablePackages) {
+        ArrayList<AndroidPackage> resultList = null;
         // Set of all descendants of a library; used to eliminate cycles
         ArraySet<String> descendants = null;
         // The current list of packages that need updating
-        ArrayList<PackageParser.Package> needsUpdating = null;
+        ArrayList<AndroidPackage> needsUpdating = null;
         if (updatedPkg != null) {
             needsUpdating = new ArrayList<>(1);
             needsUpdating.add(updatedPkg);
         }
         do {
-            final PackageParser.Package changingPkg =
+            final AndroidPackage changingPkg =
                     (needsUpdating == null) ? null : needsUpdating.remove(0);
             for (int i = mPackages.size() - 1; i >= 0; --i) {
-                final PackageParser.Package pkg = mPackages.valueAt(i);
+                final AndroidPackage pkg = mPackages.valueAt(i);
                 if (changingPkg != null
-                        && !hasString(pkg.usesLibraries, changingPkg.libraryNames)
-                        && !hasString(pkg.usesOptionalLibraries, changingPkg.libraryNames)
-                        && !ArrayUtils.contains(pkg.usesStaticLibraries,
-                                changingPkg.staticSharedLibName)) {
+                        && !hasString(pkg.getUsesLibraries(), changingPkg.getLibraryNames())
+                        && !hasString(pkg.getUsesOptionalLibraries(), changingPkg.getLibraryNames())
+                        && !ArrayUtils.contains(pkg.getUsesStaticLibraries(),
+                                changingPkg.getStaticSharedLibName())) {
                     continue;
                 }
                 if (resultList == null) {
@@ -10068,8 +10038,8 @@
                     if (descendants == null) {
                         descendants = new ArraySet<>();
                     }
-                    if (!descendants.contains(pkg.packageName)) {
-                        descendants.add(pkg.packageName);
+                    if (!descendants.contains(pkg.getPackageName())) {
+                        descendants.add(pkg.getPackageName());
                         needsUpdating.add(pkg);
                     }
                 }
@@ -10084,8 +10054,9 @@
                     if (!pkg.isSystem() || pkg.isUpdatedSystemApp()) {
                         final int flags = pkg.isUpdatedSystemApp()
                                 ? PackageManager.DELETE_KEEP_DATA : 0;
-                        deletePackageLIF(pkg.packageName, null, true, mUserManager.getUserIds(),
-                                flags , null, true, null);
+                        deletePackageLIF(pkg.getPackageName(), null, true,
+                                mUserManager.getUserIds(), flags, null,
+                                true, null);
                     }
                     Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage());
                 }
@@ -10095,43 +10066,15 @@
     }
 
     @GuardedBy({"mInstallLock", "mLock"})
-    private List<ScanResult> scanPackageTracedLI(PackageParser.Package pkg,
+    private ScanResult scanPackageTracedLI(ParsedPackage parsedPackage,
             final @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime,
             @Nullable UserHandle user) throws PackageManagerException {
         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanPackage");
-        // If the package has children and this is the first dive in the function
-        // we recursively scan the package with the SCAN_CHECK_ONLY flag set to see
-        // whether all packages (parent and children) would be successfully scanned
-        // before the actual scan since scanning mutates internal state and we want
-        // to atomically install the package and its children.
-        if ((scanFlags & SCAN_CHECK_ONLY) == 0) {
-            if (pkg.childPackages != null && pkg.childPackages.size() > 0) {
-                scanFlags |= SCAN_CHECK_ONLY;
-            }
-        } else {
-            scanFlags &= ~SCAN_CHECK_ONLY;
-        }
-
-        final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
-        final List<ScanResult> scanResults = new ArrayList<>(1 + childCount);
         try {
-            // Scan the parent
-            scanResults.add(scanPackageNewLI(pkg, parseFlags, scanFlags, currentTime, user));
-            // Scan the children
-            for (int i = 0; i < childCount; i++) {
-                PackageParser.Package childPkg = pkg.childPackages.get(i);
-                scanResults.add(scanPackageNewLI(childPkg, parseFlags,
-                        scanFlags, currentTime, user));
-            }
+            return scanPackageNewLI(parsedPackage, parseFlags, scanFlags, currentTime, user);
         } finally {
             Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
         }
-
-        if ((scanFlags & SCAN_CHECK_ONLY) != 0) {
-            return scanPackageTracedLI(pkg, parseFlags, scanFlags, currentTime, user);
-        }
-
-        return scanResults;
     }
 
     /** The result of a package scan. */
@@ -10178,9 +10121,9 @@
     @VisibleForTesting
     static class ScanRequest {
         /** The parsed package */
-        @NonNull public final PackageParser.Package pkg;
+        @NonNull public final ParsedPackage parsedPackage;
         /** The package this package replaces */
-        @Nullable public final PackageParser.Package oldPkg;
+        @Nullable public final AndroidPackage oldPkg;
         /** Shared user settings, if the package has a shared user */
         @Nullable public final SharedUserSetting sharedUserSetting;
         /**
@@ -10204,9 +10147,9 @@
         /** Whether or not the platform package is being scanned */
         public final boolean isPlatformPackage;
         public ScanRequest(
-                @NonNull PackageParser.Package pkg,
+                @NonNull ParsedPackage parsedPackage,
                 @Nullable SharedUserSetting sharedUserSetting,
-                @Nullable PackageParser.Package oldPkg,
+                @Nullable AndroidPackage oldPkg,
                 @Nullable PackageSetting pkgSetting,
                 @Nullable PackageSetting disabledPkgSetting,
                 @Nullable PackageSetting originalPkgSetting,
@@ -10215,7 +10158,7 @@
                 @ScanFlags int scanFlags,
                 boolean isPlatformPackage,
                 @Nullable UserHandle user) {
-            this.pkg = pkg;
+            this.parsedPackage = parsedPackage;
             this.oldPkg = oldPkg;
             this.pkgSetting = pkgSetting;
             this.sharedUserSetting = sharedUserSetting;
@@ -10248,7 +10191,7 @@
      */
     private @ScanFlags int adjustScanFlags(@ScanFlags int scanFlags,
             PackageSetting pkgSetting, PackageSetting disabledPkgSetting, UserHandle user,
-            PackageParser.Package pkg) {
+            AndroidPackage pkg) {
 
         // TODO(patb): Do away entirely with disabledPkgSetting here. PkgSetting will always contain
         // the correct isSystem value now that we don't disable system packages before scan.
@@ -10300,12 +10243,14 @@
                 && SystemProperties.getInt("ro.vndk.version", 28) < 28;
         if (((scanFlags & SCAN_AS_PRIVILEGED) == 0)
                 && !pkg.isPrivileged()
-                && (pkg.mSharedUserId != null)
+                && (pkg.getSharedUserId() != null)
                 && !skipVendorPrivilegeScan) {
             SharedUserSetting sharedUserSetting = null;
             try {
-                sharedUserSetting = mSettings.getSharedUserLPw(pkg.mSharedUserId, 0, 0, false);
-            } catch (PackageManagerException ignore) {}
+                sharedUserSetting = mSettings.getSharedUserLPw(pkg.getSharedUserId(), 0,
+                        0, false);
+            } catch (PackageManagerException ignore) {
+            }
             if (sharedUserSetting != null && sharedUserSetting.isPrivileged()) {
                 // Exempt SharedUsers signed with the platform key.
                 // TODO(b/72378145) Fix this exemption. Force signature apps
@@ -10314,7 +10259,8 @@
                 synchronized (mLock) {
                     PackageSetting platformPkgSetting = mSettings.mPackages.get("android");
                     if ((compareSignatures(platformPkgSetting.signatures.mSigningDetails.signatures,
-                                pkg.mSigningDetails.signatures) != PackageManager.SIGNATURE_MATCH)) {
+                            pkg.getSigningDetails().signatures)
+                            != PackageManager.SIGNATURE_MATCH)) {
                         scanFlags |= SCAN_AS_PRIVILEGED;
                     }
                 }
@@ -10329,46 +10275,50 @@
     // method. Also, we need to solve the problem of potentially creating a new shared user
     // setting. That can probably be done later and patch things up after the fact.
     @GuardedBy({"mInstallLock", "mLock"})
-    private ScanResult scanPackageNewLI(@NonNull PackageParser.Package pkg,
+    private ScanResult scanPackageNewLI(@NonNull ParsedPackage parsedPackage,
             final @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime,
             @Nullable UserHandle user) throws PackageManagerException {
 
-        final String renamedPkgName = mSettings.getRenamedPackageLPr(pkg.mRealPackage);
-        final String realPkgName = getRealPackageName(pkg, renamedPkgName);
+        final String renamedPkgName = mSettings.getRenamedPackageLPr(
+                parsedPackage.getRealPackage());
+        final String realPkgName = getRealPackageName(parsedPackage, renamedPkgName);
         if (realPkgName != null) {
-            ensurePackageRenamed(pkg, renamedPkgName);
+            ensurePackageRenamed(parsedPackage, renamedPkgName);
         }
-        final PackageSetting originalPkgSetting = getOriginalPackageLocked(pkg, renamedPkgName);
-        final PackageSetting pkgSetting = mSettings.getPackageLPr(pkg.packageName);
+        final PackageSetting originalPkgSetting = getOriginalPackageLocked(parsedPackage,
+                renamedPkgName);
+        final PackageSetting pkgSetting = mSettings.getPackageLPr(parsedPackage.getPackageName());
         final PackageSetting disabledPkgSetting =
-                mSettings.getDisabledSystemPkgLPr(pkg.packageName);
+                mSettings.getDisabledSystemPkgLPr(parsedPackage.getPackageName());
 
-        if (mTransferedPackages.contains(pkg.packageName)) {
-            Slog.w(TAG, "Package " + pkg.packageName
+        if (mTransferedPackages.contains(parsedPackage.getPackageName())) {
+            Slog.w(TAG, "Package " + parsedPackage.getPackageName()
                     + " was transferred to another, but its .apk remains");
         }
 
-        scanFlags = adjustScanFlags(scanFlags, pkgSetting, disabledPkgSetting, user, pkg);
+        scanFlags = adjustScanFlags(scanFlags, pkgSetting, disabledPkgSetting, user, parsedPackage);
         synchronized (mLock) {
-            applyPolicy(pkg, parseFlags, scanFlags, mPlatformPackage);
-            assertPackageIsValid(pkg, parseFlags, scanFlags);
+            applyPolicy(parsedPackage, parseFlags, scanFlags, mPlatformPackage);
+            assertPackageIsValid(parsedPackage, parseFlags, scanFlags);
 
             SharedUserSetting sharedUserSetting = null;
-            if (pkg.mSharedUserId != null) {
+            if (parsedPackage.getSharedUserId() != null) {
                 // SIDE EFFECTS; may potentially allocate a new shared user
-                sharedUserSetting = mSettings.getSharedUserLPw(
-                        pkg.mSharedUserId, 0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/, true /*create*/);
+                sharedUserSetting = mSettings.getSharedUserLPw(parsedPackage.getSharedUserId(),
+                        0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/, true /*create*/);
                 if (DEBUG_PACKAGE_SCANNING) {
                     if ((parseFlags & PackageParser.PARSE_CHATTY) != 0)
-                        Log.d(TAG, "Shared UserID " + pkg.mSharedUserId
+                        Log.d(TAG, "Shared UserID " + parsedPackage.getSharedUserId()
                                 + " (uid=" + sharedUserSetting.userId + "):"
                                 + " packages=" + sharedUserSetting.packages);
                 }
             }
-            final ScanRequest request = new ScanRequest(pkg, sharedUserSetting,
+            String platformPackageName = mPlatformPackage == null
+                    ? null : mPlatformPackage.getPackageName();
+            final ScanRequest request = new ScanRequest(parsedPackage, sharedUserSetting,
                     pkgSetting == null ? null : pkgSetting.pkg, pkgSetting, disabledPkgSetting,
                     originalPkgSetting, realPkgName, parseFlags, scanFlags,
-                    (pkg == mPlatformPackage), user);
+                    Objects.equals(parsedPackage.getPackageName(), platformPackageName), user);
             return scanPackageOnlyLI(request, mInjector, mFactoryTest, currentTime);
         }
     }
@@ -10411,11 +10361,18 @@
      * possible and the system is not left in an inconsistent state.
      */
     @GuardedBy({"mLock", "mInstallLock"})
-    private void commitReconciledScanResultLocked(@NonNull ReconciledPackage reconciledPkg) {
+    private AndroidPackage commitReconciledScanResultLocked(
+            @NonNull ReconciledPackage reconciledPkg) {
         final ScanResult result = reconciledPkg.scanResult;
         final ScanRequest request = result.request;
-        final PackageParser.Package pkg = request.pkg;
-        final PackageParser.Package oldPkg = request.oldPkg;
+        // TODO(b/135203078): Move this even further away
+        ParsedPackage parsedPackage = request.parsedPackage;
+        if ("android".equals(parsedPackage.getPackageName())) {
+            // TODO(b/135203078): Move this to initial parse
+            parsedPackage.setVersionCode(mSdkVersion)
+                    .setVersionCodeMajor(0);
+        }
+        final AndroidPackage oldPkg = request.oldPkg;
         final @ParseFlags int parseFlags = request.parseFlags;
         final @ScanFlags int scanFlags = request.scanFlags;
         final PackageSetting oldPkgSetting = request.oldPkgSetting;
@@ -10432,13 +10389,11 @@
         if (result.existingSettingCopied) {
             pkgSetting = request.pkgSetting;
             pkgSetting.updateFrom(result.pkgSetting);
-            pkg.mExtras = pkgSetting;
         } else {
             pkgSetting = result.pkgSetting;
             if (originalPkgSetting != null) {
-                mSettings.addRenamedPackageLPw(pkg.packageName, originalPkgSetting.name);
-            }
-            if (originalPkgSetting != null && (scanFlags & SCAN_CHECK_ONLY) == 0) {
+                mSettings.addRenamedPackageLPw(parsedPackage.getPackageName(),
+                        originalPkgSetting.name);
                 mTransferedPackages.add(originalPkgSetting.name);
             }
         }
@@ -10451,12 +10406,13 @@
         // We need to have this here because addUserToSettingLPw() is sometimes responsible
         // for creating the application ID. If we did this earlier, we would be saving the
         // correct ID.
-        pkg.applicationInfo.uid = pkgSetting.appId;
+        parsedPackage.setUid(pkgSetting.appId);
+        final AndroidPackage pkg = parsedPackage.hideAsFinal();
 
         mSettings.writeUserRestrictionsLPw(pkgSetting, oldPkgSetting);
 
-        if ((scanFlags & SCAN_CHECK_ONLY) == 0 && realPkgName != null) {
-            mTransferedPackages.add(pkg.packageName);
+        if (realPkgName != null) {
+            mTransferedPackages.add(pkg.getPackageName());
         }
 
         if (reconciledPkg.collectedSharedLibraryInfos != null) {
@@ -10465,7 +10421,7 @@
 
         final KeySetManagerService ksms = mSettings.mKeySetManagerService;
         if (reconciledPkg.removeAppKeySetData) {
-            ksms.removeAppKeySetDataLPw(pkg.packageName);
+            ksms.removeAppKeySetDataLPw(pkg.getPackageName());
         }
         if (reconciledPkg.sharedUserSignaturesChanged) {
             pkgSetting.sharedUser.signaturesChanged = Boolean.TRUE;
@@ -10473,17 +10429,17 @@
         }
         pkgSetting.signatures.mSigningDetails = reconciledPkg.signingDetails;
 
-        if ((scanFlags & SCAN_CHECK_ONLY) == 0 && pkg.mAdoptPermissions != null) {
+        if (pkg.getAdoptPermissions() != null) {
             // This package wants to adopt ownership of permissions from
             // another package.
-            for (int i = pkg.mAdoptPermissions.size() - 1; i >= 0; i--) {
-                final String origName = pkg.mAdoptPermissions.get(i);
+            for (int i = pkg.getAdoptPermissions().size() - 1; i >= 0; i--) {
+                final String origName = pkg.getAdoptPermissions().get(i);
                 final PackageSetting orig = mSettings.getPackageLPr(origName);
                 if (orig != null) {
                     if (verifyPackageUpdateLPr(orig, pkg)) {
                         Slog.i(TAG, "Adopting permissions from " + origName + " to "
-                                + pkg.packageName);
-                        mSettings.mPermissions.transferPermissions(origName, pkg.packageName);
+                                + pkg.getPackageName());
+                        mSettings.mPermissions.transferPermissions(origName, pkg.getPackageName());
                     }
                 }
             }
@@ -10500,21 +10456,15 @@
             }
         }
 
-        if ((scanFlags & SCAN_CHECK_ONLY) != 0) {
-            if (oldPkgSetting != null) {
-                synchronized (mLock) {
-                    mSettings.mPackages.put(oldPkgSetting.name, oldPkgSetting);
-                }
-            }
-        } else {
-            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);
-            if (pkgSetting.getInstantApp(userId)) {
-                mInstantAppRegistry.addInstantAppLPw(userId, pkgSetting.appId);
-            }
+        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);
+        if (pkgSetting.getInstantApp(userId)) {
+            mInstantAppRegistry.addInstantAppLPw(userId, pkgSetting.appId);
         }
+
+        return pkg;
     }
 
     /**
@@ -10522,18 +10472,19 @@
      * <p>This may differ from the package's actual name if the application has already
      * been installed under one of this package's original names.
      */
-    private static @Nullable String getRealPackageName(@NonNull PackageParser.Package pkg,
+    private static @Nullable String getRealPackageName(@NonNull AndroidPackage pkg,
             @Nullable String renamedPkgName) {
         if (isPackageRenamed(pkg, renamedPkgName)) {
-            return pkg.mRealPackage;
+            return pkg.getRealPackage();
         }
         return null;
     }
 
     /** Returns {@code true} if the package has been renamed. Otherwise, {@code false}. */
-    private static boolean isPackageRenamed(@NonNull PackageParser.Package pkg,
+    private static boolean isPackageRenamed(@NonNull AndroidPackage pkg,
             @Nullable String renamedPkgName) {
-        return pkg.mOriginalPackages != null && pkg.mOriginalPackages.contains(renamedPkgName);
+        return pkg.getOriginalPackages() != null
+                && pkg.getOriginalPackages().contains(renamedPkgName);
     }
 
     /**
@@ -10544,14 +10495,14 @@
      * shared user [if any].
      */
     @GuardedBy("mLock")
-    private @Nullable PackageSetting getOriginalPackageLocked(@NonNull PackageParser.Package pkg,
+    private @Nullable PackageSetting getOriginalPackageLocked(@NonNull AndroidPackage pkg,
             @Nullable String renamedPkgName) {
         if (!isPackageRenamed(pkg, renamedPkgName)) {
             return null;
         }
-        for (int i = pkg.mOriginalPackages.size() - 1; i >= 0; --i) {
+        for (int i = ArrayUtils.size(pkg.getOriginalPackages()) - 1; i >= 0; --i) {
             final PackageSetting originalPs =
-                    mSettings.getPackageLPr(pkg.mOriginalPackages.get(i));
+                    mSettings.getPackageLPr(pkg.getOriginalPackages().get(i));
             if (originalPs != null) {
                 // the package is already installed under its original name...
                 // but, should we use it?
@@ -10559,18 +10510,18 @@
                     // the new package is incompatible with the original
                     continue;
                 } else if (originalPs.sharedUser != null) {
-                    if (!originalPs.sharedUser.name.equals(pkg.mSharedUserId)) {
+                    if (!originalPs.sharedUser.name.equals(pkg.getSharedUserId())) {
                         // the shared user id is incompatible with the original
                         Slog.w(TAG, "Unable to migrate data from " + originalPs.name
-                                + " to " + pkg.packageName + ": old uid "
+                                + " to " + pkg.getPackageName() + ": old uid "
                                 + originalPs.sharedUser.name
-                                + " differs from " + pkg.mSharedUserId);
+                                + " differs from " + pkg.getSharedUserId());
                         continue;
                     }
                     // TODO: Add case when shared user id is added [b/28144775]
                 } else {
                     if (DEBUG_UPGRADE) Log.v(TAG, "Renaming new package "
-                            + pkg.packageName + " to old name " + originalPs.name);
+                            + pkg.getPackageName() + " to old name " + originalPs.name);
                 }
                 return originalPs;
             }
@@ -10583,19 +10534,19 @@
      * <p>When we've already installed the package under an original name, update
      * the new package so we can continue to have the old name.
      */
-    private static void ensurePackageRenamed(@NonNull PackageParser.Package pkg,
+    private static void ensurePackageRenamed(@NonNull ParsedPackage parsedPackage,
             @NonNull String renamedPackageName) {
-        if (pkg.mOriginalPackages == null
-                || !pkg.mOriginalPackages.contains(renamedPackageName)
-                || pkg.packageName.equals(renamedPackageName)) {
+        if (parsedPackage.getOriginalPackages() == null
+                || !parsedPackage.getOriginalPackages().contains(renamedPackageName)
+                || parsedPackage.getPackageName().equals(renamedPackageName)) {
             return;
         }
-        pkg.setPackageName(renamedPackageName);
+        parsedPackage.setPackageName(renamedPackageName);
     }
 
     /**
      * Applies the adjusted ABI calculated by
-     * {@link PackageAbiHelper#getAdjustedAbiForSharedUser(Set, PackageParser.Package)} to all
+     * {@link PackageAbiHelper#getAdjustedAbiForSharedUser(Set, AndroidPackage)} to all
      * relevant packages and settings.
      * @param sharedUserSetting The {@code SharedUserSetting} to adjust
      * @param scannedPackage the package being scanned or null
@@ -10603,22 +10554,20 @@
      * @return the list of code paths that belong to packages that had their ABIs adjusted.
      */
     private static List<String> applyAdjustedAbiToSharedUser(SharedUserSetting sharedUserSetting,
-            PackageParser.Package scannedPackage, String adjustedAbi) {
+            ParsedPackage scannedPackage, String adjustedAbi) {
         if (scannedPackage != null)  {
-            scannedPackage.applicationInfo.primaryCpuAbi = adjustedAbi;
+            scannedPackage.setPrimaryCpuAbi(adjustedAbi);
         }
         List<String> changedAbiCodePath = null;
         for (PackageSetting ps : sharedUserSetting.packages) {
-            if (scannedPackage == null || !scannedPackage.packageName.equals(ps.name)) {
+            if (scannedPackage == null || !scannedPackage.getPackageName().equals(ps.name)) {
                 if (ps.primaryCpuAbiString != null) {
                     continue;
                 }
 
                 ps.primaryCpuAbiString = adjustedAbi;
-                if (ps.pkg != null && ps.pkg.applicationInfo != null
-                        && !TextUtils.equals(
-                        adjustedAbi, ps.pkg.applicationInfo.primaryCpuAbi)) {
-                    ps.pkg.applicationInfo.primaryCpuAbi = adjustedAbi;
+                if (ps.pkg != null && !TextUtils.equals(adjustedAbi, ps.pkg.getPrimaryCpuAbi())) {
+                    ps.pkg.mutate().setPrimaryCpuAbi(adjustedAbi);
                     if (DEBUG_ABI_SELECTION) {
                         Slog.i(TAG,
                                 "Adjusting ABI for " + ps.name + " to " + adjustedAbi
@@ -10702,7 +10651,7 @@
             throws PackageManagerException {
         final PackageAbiHelper packageAbiHelper = injector.getAbiHelper();
         final UserManagerInternal userManager = injector.getUserManagerInternal();
-        final PackageParser.Package pkg = request.pkg;
+        ParsedPackage parsedPackage = request.parsedPackage;
         PackageSetting pkgSetting = request.pkgSetting;
         final PackageSetting disabledPkgSetting = request.disabledPkgSetting;
         final PackageSetting originalPkgSetting = request.originalPkgSetting;
@@ -10717,13 +10666,12 @@
 
         if (DEBUG_PACKAGE_SCANNING) {
             if ((parseFlags & PackageParser.PARSE_CHATTY) != 0)
-                Log.d(TAG, "Scanning package " + pkg.packageName);
+                Log.d(TAG, "Scanning package " + parsedPackage.getPackageName());
         }
 
         // Initialize package source and resource directories
-        final File scanFile = new File(pkg.codePath);
-        final File destCodeFile = new File(pkg.applicationInfo.getCodePath());
-        final File destResourceFile = new File(pkg.applicationInfo.getResourcePath());
+        final File destCodeFile = new File(parsedPackage.getAppInfoCodePath());
+        final File destResourceFile = new File(parsedPackage.getAppInfoResourcePath());
 
         // We keep references to the derived CPU Abis from settings in oder to reuse
         // them in the case where we're not upgrading or booting for the first time.
@@ -10742,7 +10690,7 @@
 
         if (pkgSetting != null && pkgSetting.sharedUser != sharedUserSetting) {
             PackageManagerService.reportSettingsProblem(Log.WARN,
-                    "Package " + pkg.packageName + " shared user changed from "
+                    "Package " + parsedPackage.getPackageName() + " shared user changed from "
                             + (pkgSetting.sharedUser != null
                             ? pkgSetting.sharedUser.name : "<nothing>")
                             + " to "
@@ -10752,30 +10700,28 @@
         }
 
         String[] usesStaticLibraries = null;
-        if (pkg.usesStaticLibraries != null) {
-            usesStaticLibraries = new String[pkg.usesStaticLibraries.size()];
-            pkg.usesStaticLibraries.toArray(usesStaticLibraries);
+        if (parsedPackage.getUsesStaticLibraries() != null) {
+            usesStaticLibraries = new String[parsedPackage.getUsesStaticLibraries().size()];
+            parsedPackage.getUsesStaticLibraries().toArray(usesStaticLibraries);
         }
         final boolean createNewPackage = (pkgSetting == null);
         if (createNewPackage) {
-            final String parentPackageName = (pkg.parentPackage != null)
-                    ? pkg.parentPackage.packageName : null;
             final boolean instantApp = (scanFlags & SCAN_AS_INSTANT_APP) != 0;
             final boolean virtualPreload = (scanFlags & SCAN_AS_VIRTUAL_PRELOAD) != 0;
             // REMOVE SharedUserSetting from method; update in a separate call
-            pkgSetting = Settings.createNewSetting(pkg.packageName, originalPkgSetting,
-                    disabledPkgSetting, realPkgName, sharedUserSetting, destCodeFile,
-                    destResourceFile, pkg.applicationInfo.nativeLibraryRootDir,
-                    pkg.applicationInfo.primaryCpuAbi, pkg.applicationInfo.secondaryCpuAbi,
-                    pkg.mVersionCode, pkg.applicationInfo.flags, pkg.applicationInfo.privateFlags,
-                    user, true /*allowInstall*/, instantApp, virtualPreload,
-                    parentPackageName, pkg.getChildPackageNames(),
-                    UserManagerService.getInstance(), usesStaticLibraries,
-                    pkg.usesStaticLibrariesVersions);
+            pkgSetting = Settings.createNewSetting(parsedPackage.getPackageName(),
+                    originalPkgSetting, disabledPkgSetting, realPkgName, sharedUserSetting,
+                    destCodeFile, destResourceFile, parsedPackage.getNativeLibraryRootDir(),
+                    parsedPackage.getPrimaryCpuAbi(), parsedPackage.getSecondaryCpuAbi(),
+                    parsedPackage.getVersionCode(), parsedPackage.getFlags(),
+                    parsedPackage.getPrivateFlags(), user, true /*allowInstall*/, instantApp,
+                    virtualPreload, UserManagerService.getInstance(), usesStaticLibraries,
+                    parsedPackage.getUsesStaticLibrariesVersions());
         } else {
             // make a deep copy to avoid modifying any existing system state.
             pkgSetting = new PackageSetting(pkgSetting);
-            pkgSetting.pkg = pkg;
+            // TODO(b/135203078): Remove entirely. Set package directly.
+            parsedPackage.setPackageSettingCallback(pkgSetting);
 
             // REMOVE SharedUserSetting from method; update in a separate call.
             //
@@ -10783,18 +10729,18 @@
             // secondaryCpuAbi are not known at this point so we always update them
             // to null here, only to reset them at a later point.
             Settings.updatePackageSetting(pkgSetting, disabledPkgSetting, sharedUserSetting,
-                    destCodeFile, destResourceFile, pkg.applicationInfo.nativeLibraryDir,
-                    pkg.applicationInfo.primaryCpuAbi, pkg.applicationInfo.secondaryCpuAbi,
-                    pkg.applicationInfo.flags, pkg.applicationInfo.privateFlags,
-                    pkg.getChildPackageNames(), UserManagerService.getInstance(),
-                    usesStaticLibraries, pkg.usesStaticLibrariesVersions);
+                    destCodeFile, destResourceFile, parsedPackage.getNativeLibraryDir(),
+                    parsedPackage.getPrimaryCpuAbi(), parsedPackage.getSecondaryCpuAbi(),
+                    parsedPackage.getFlags(), parsedPackage.getPrivateFlags(),
+                    UserManagerService.getInstance(),
+                    usesStaticLibraries, parsedPackage.getUsesStaticLibrariesVersions());
         }
         if (createNewPackage && originalPkgSetting != null) {
             // This is the initial transition from the original package, so,
             // fix up the new package's name now. We must do this after looking
             // up the package under its new name, so getPackageLP takes care of
             // fiddling things correctly.
-            pkg.setPackageName(originalPkgSetting.name);
+            parsedPackage.setPackageName(originalPkgSetting.name);
 
             // File a report about this.
             String msg = "New package " + pkgSetting.realName
@@ -10813,7 +10759,7 @@
         if (disabledPkgSetting != null
                 || (0 != (scanFlags & SCAN_NEW_INSTALL)
                 && pkgSetting != null && pkgSetting.isSystem())) {
-            pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
+            parsedPackage.mutate().setUpdatedSystemApp(true);
         }
 
         pkg.applicationInfo.seInfo = SELinuxMMAC.getSeInfo(pkg, sharedUserSetting,
@@ -10828,7 +10774,7 @@
 
         if (!isPlatformPackage) {
             // Get all of our default paths setup
-            pkg.applicationInfo.initForUser(UserHandle.USER_SYSTEM);
+            parsedPackage.initForUser(UserHandle.USER_SYSTEM);
         }
 
         if (pkg.isSystem()) {
@@ -10840,41 +10786,43 @@
         if ((scanFlags & SCAN_NEW_INSTALL) == 0) {
             if (needToDeriveAbi) {
                 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "derivePackageAbi");
-                final boolean extractNativeLibs = !pkg.isLibrary();
+                final boolean extractNativeLibs = !parsedPackage.isLibrary();
                 final Pair<PackageAbiHelper.Abis, PackageAbiHelper.NativeLibraryPaths> derivedAbi =
-                        packageAbiHelper.derivePackageAbi(pkg, cpuAbiOverride, extractNativeLibs);
-                derivedAbi.first.applyTo(pkg);
-                derivedAbi.second.applyTo(pkg);
+                        packageAbiHelper.derivePackageAbi(parsedPackage, cpuAbiOverride,
+                                extractNativeLibs);
+                derivedAbi.first.applyTo(parsedPackage);
+                derivedAbi.second.applyTo(parsedPackage);
                 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
 
                 // Some system apps still use directory structure for native libraries
                 // in which case we might end up not detecting abi solely based on apk
                 // structure. Try to detect abi based on directory structure.
-                if (isSystemApp(pkg) && !pkg.isUpdatedSystemApp() &&
-                        pkg.applicationInfo.primaryCpuAbi == null) {
+                if (isSystemApp(parsedPackage) && !parsedPackage.isUpdatedSystemApp() &&
+                        parsedPackage.getPrimaryCpuAbi() == null) {
                     final PackageAbiHelper.Abis abis = packageAbiHelper.getBundledAppAbis(
-                            pkg);
-                    abis.applyTo(pkg);
+                            parsedPackage);
+                    abis.applyTo(parsedPackage);
                     abis.applyTo(pkgSetting);
                     final PackageAbiHelper.NativeLibraryPaths nativeLibraryPaths =
-                            packageAbiHelper.getNativeLibraryPaths(pkg, sAppLib32InstallDir);
-                    nativeLibraryPaths.applyTo(pkg);
+                            packageAbiHelper.getNativeLibraryPaths(parsedPackage,
+                                    sAppLib32InstallDir);
+                    nativeLibraryPaths.applyTo(parsedPackage);
                 }
             } else {
                 // This is not a first boot or an upgrade, don't bother deriving the
                 // ABI during the scan. Instead, trust the value that was stored in the
                 // package setting.
-                pkg.applicationInfo.primaryCpuAbi = primaryCpuAbiFromSettings;
-                pkg.applicationInfo.secondaryCpuAbi = secondaryCpuAbiFromSettings;
+                parsedPackage.setPrimaryCpuAbi(primaryCpuAbiFromSettings)
+                        .setSecondaryCpuAbi(secondaryCpuAbiFromSettings);
 
                 final PackageAbiHelper.NativeLibraryPaths nativeLibraryPaths =
-                        packageAbiHelper.getNativeLibraryPaths(pkg, sAppLib32InstallDir);
-                nativeLibraryPaths.applyTo(pkg);
+                        packageAbiHelper.getNativeLibraryPaths(parsedPackage, sAppLib32InstallDir);
+                nativeLibraryPaths.applyTo(parsedPackage);
 
                 if (DEBUG_ABI_SELECTION) {
                     Slog.i(TAG, "Using ABIS and native lib paths from settings : " +
-                            pkg.packageName + " " + pkg.applicationInfo.primaryCpuAbi + ", " +
-                            pkg.applicationInfo.secondaryCpuAbi);
+                            parsedPackage.getPackageName() + " " + parsedPackage.getPrimaryCpuAbi()
+                            + ", " + parsedPackage.getSecondaryCpuAbi());
                 }
             }
         } else {
@@ -10882,8 +10830,8 @@
                 // We haven't run dex-opt for this move (since we've moved the compiled output too)
                 // but we already have this packages package info in the PackageSetting. We just
                 // use that and derive the native library path based on the new codepath.
-                pkg.applicationInfo.primaryCpuAbi = pkgSetting.primaryCpuAbiString;
-                pkg.applicationInfo.secondaryCpuAbi = pkgSetting.secondaryCpuAbiString;
+                parsedPackage.setPrimaryCpuAbi(pkgSetting.primaryCpuAbiString)
+                        .setSecondaryCpuAbi(pkgSetting.secondaryCpuAbiString);
             }
 
             // Set native library paths again. For moves, the path will be updated based on the
@@ -10891,8 +10839,8 @@
             // ABIs we determined during compilation, but the path will depend on the final
             // package path (after the rename away from the stage path).
             final PackageAbiHelper.NativeLibraryPaths nativeLibraryPaths =
-                    packageAbiHelper.getNativeLibraryPaths(pkg, sAppLib32InstallDir);
-            nativeLibraryPaths.applyTo(pkg);
+                    packageAbiHelper.getNativeLibraryPaths(parsedPackage, sAppLib32InstallDir);
+            nativeLibraryPaths.applyTo(parsedPackage);
         }
 
         // This is a special case for the "system" package, where the ABI is
@@ -10900,8 +10848,8 @@
         // of this ABI so that we can deal with "normal" applications that run under
         // the same UID correctly.
         if (isPlatformPackage) {
-            pkg.applicationInfo.primaryCpuAbi = VMRuntime.getRuntime().is64Bit() ?
-                    Build.SUPPORTED_64_BIT_ABIS[0] : Build.SUPPORTED_32_BIT_ABIS[0];
+            parsedPackage.setPrimaryCpuAbi(VMRuntime.getRuntime().is64Bit() ?
+                    Build.SUPPORTED_64_BIT_ABIS[0] : Build.SUPPORTED_32_BIT_ABIS[0]);
         }
 
         // If there's a mismatch between the abi-override in the package setting
@@ -10909,34 +10857,34 @@
         // would've already compiled the app without taking the package setting into
         // account.
         if ((scanFlags & SCAN_NO_DEX) == 0 && (scanFlags & SCAN_NEW_INSTALL) != 0) {
-            if (cpuAbiOverride == null && pkg.packageName != null) {
+            if (cpuAbiOverride == null && parsedPackage.getPackageName() != null) {
                 Slog.w(TAG, "Ignoring persisted ABI override " + cpuAbiOverride +
-                        " for package " + pkg.packageName);
+                        " for package " + parsedPackage.getPackageName());
             }
         }
 
-        pkgSetting.primaryCpuAbiString = pkg.applicationInfo.primaryCpuAbi;
-        pkgSetting.secondaryCpuAbiString = pkg.applicationInfo.secondaryCpuAbi;
+        pkgSetting.primaryCpuAbiString = parsedPackage.getPrimaryCpuAbi();
+        pkgSetting.secondaryCpuAbiString = parsedPackage.getSecondaryCpuAbi();
         pkgSetting.cpuAbiOverrideString = cpuAbiOverride;
 
         // Copy the derived override back to the parsed package, so that we can
         // update the package settings accordingly.
-        pkg.cpuAbiOverride = cpuAbiOverride;
+        parsedPackage.setCpuAbiOverride(cpuAbiOverride);
 
         if (DEBUG_ABI_SELECTION) {
-            Slog.d(TAG, "Resolved nativeLibraryRoot for " + pkg.packageName
-                    + " to root=" + pkg.applicationInfo.nativeLibraryRootDir + ", isa="
-                    + pkg.applicationInfo.nativeLibraryRootRequiresIsa);
+            Slog.d(TAG, "Resolved nativeLibraryRoot for " + parsedPackage.getPackageName()
+                    + " to root=" + parsedPackage.getNativeLibraryRootDir() + ", isa="
+                    + parsedPackage.isNativeLibraryRootRequiresIsa());
         }
 
         // Push the derived path down into PackageSettings so we know what to
         // clean up at uninstall time.
-        pkgSetting.legacyNativeLibraryPathString = pkg.applicationInfo.nativeLibraryRootDir;
+        pkgSetting.legacyNativeLibraryPathString = parsedPackage.getNativeLibraryRootDir();
 
         if (DEBUG_ABI_SELECTION) {
-            Log.d(TAG, "Abis for package[" + pkg.packageName + "] are" +
-                    " primary=" + pkg.applicationInfo.primaryCpuAbi +
-                    " secondary=" + pkg.applicationInfo.secondaryCpuAbi);
+            Log.d(TAG, "Abis for package[" + parsedPackage.getPackageName() + "] are" +
+                    " primary=" + parsedPackage.getPrimaryCpuAbi() +
+                    " secondary=" + parsedPackage.getSecondaryCpuAbi());
         }
 
         if ((scanFlags & SCAN_BOOTING) == 0 && pkgSetting.sharedUser != null) {
@@ -10946,22 +10894,20 @@
             // We also do this *before* we perform dexopt on this package, so that
             // we can avoid redundant dexopts, and also to make sure we've got the
             // code and package path correct.
-            changedAbiCodePath = applyAdjustedAbiToSharedUser(pkgSetting.sharedUser, pkg,
+            changedAbiCodePath = applyAdjustedAbiToSharedUser(pkgSetting.sharedUser, parsedPackage,
                     packageAbiHelper.getAdjustedAbiForSharedUser(
-                            pkgSetting.sharedUser.packages, pkg));
+                            pkgSetting.sharedUser.packages, parsedPackage));
         }
 
-        if (isUnderFactoryTest && pkg.requestedPermissions.contains(
-                android.Manifest.permission.FACTORY_TEST)) {
-            pkg.applicationInfo.flags |= ApplicationInfo.FLAG_FACTORY_TEST;
-        }
+        parsedPackage.setFactoryTest(isUnderFactoryTest && parsedPackage.getRequestedPermissions()
+                .contains(android.Manifest.permission.FACTORY_TEST));
 
         if (isSystemApp(pkg)) {
             pkgSetting.setIsOrphaned(true);
         }
 
         // Take care of first install / last update times.
-        final long scanFileTime = getLastModifiedTime(pkg);
+        final long scanFileTime = getLastModifiedTime(parsedPackage);
         if (currentTime != 0) {
             if (pkgSetting.firstInstallTime == 0) {
                 pkgSetting.firstInstallTime = pkgSetting.lastUpdateTime = currentTime;
@@ -10979,32 +10925,33 @@
             }
         }
         pkgSetting.setTimeStamp(scanFileTime);
-
-        pkgSetting.pkg = pkg;
-        pkgSetting.pkgFlags = pkg.applicationInfo.flags;
-        if (pkg.getLongVersionCode() != pkgSetting.versionCode) {
-            pkgSetting.versionCode = pkg.getLongVersionCode();
+        // TODO(b/135203078): Remove, move to constructor
+        parsedPackage.setPackageSettingCallback(pkgSetting);
+        pkgSetting.pkgFlags = parsedPackage.getFlags();
+        if (parsedPackage.getLongVersionCode() != pkgSetting.versionCode) {
+            pkgSetting.versionCode = parsedPackage.getLongVersionCode();
         }
         // Update volume if needed
-        final String volumeUuid = pkg.applicationInfo.volumeUuid;
+        final String volumeUuid = parsedPackage.getApplicationInfoVolumeUuid();
         if (!Objects.equals(volumeUuid, pkgSetting.volumeUuid)) {
             Slog.i(PackageManagerService.TAG,
                     "Update" + (pkgSetting.isSystem() ? " system" : "")
-                    + " package " + pkg.packageName
+                    + " package " + parsedPackage.getPackageName()
                     + " volume from " + pkgSetting.volumeUuid
                     + " to " + volumeUuid);
             pkgSetting.volumeUuid = volumeUuid;
         }
 
         SharedLibraryInfo staticSharedLibraryInfo = null;
-        if (!TextUtils.isEmpty(pkg.staticSharedLibName)) {
-            staticSharedLibraryInfo = SharedLibraryInfo.createForStatic(pkg);
+        if (!TextUtils.isEmpty(parsedPackage.getStaticSharedLibName())) {
+            staticSharedLibraryInfo = SharedLibraryInfo.createForStatic(parsedPackage);
         }
         List<SharedLibraryInfo> dynamicSharedLibraryInfos = null;
-        if (!ArrayUtils.isEmpty(pkg.libraryNames)) {
-            dynamicSharedLibraryInfos = new ArrayList<>(pkg.libraryNames.size());
-            for (String name : pkg.libraryNames) {
-                dynamicSharedLibraryInfos.add(SharedLibraryInfo.createForDynamic(pkg, name));
+        if (!ArrayUtils.isEmpty(parsedPackage.getLibraryNames())) {
+            dynamicSharedLibraryInfos = new ArrayList<>(parsedPackage.getLibraryNames().size());
+            for (String name : parsedPackage.getLibraryNames()) {
+                dynamicSharedLibraryInfos.add(
+                        SharedLibraryInfo.createForDynamic(parsedPackage, name));
             }
         }
 
@@ -11040,22 +10987,21 @@
      *
      * @throws PackageManagerException If bytecode could not be found when it should exist
      */
-    private static void assertCodePolicy(PackageParser.Package pkg)
+    private static void assertCodePolicy(AndroidPackage pkg)
             throws PackageManagerException {
-        final boolean shouldHaveCode =
-                (pkg.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0;
-        if (shouldHaveCode && !apkHasCode(pkg.baseCodePath)) {
+        final boolean shouldHaveCode = (pkg.getFlags() & ApplicationInfo.FLAG_HAS_CODE) != 0;
+        if (shouldHaveCode && !apkHasCode(pkg.getBaseCodePath())) {
             throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
-                    "Package " + pkg.baseCodePath + " code is missing");
+                    "Package " + pkg.getBaseCodePath() + " code is missing");
         }
 
-        if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) {
-            for (int i = 0; i < pkg.splitCodePaths.length; i++) {
+        if (!ArrayUtils.isEmpty(pkg.getSplitCodePaths())) {
+            for (int i = 0; i < pkg.getSplitCodePaths().length; i++) {
                 final boolean splitShouldHaveCode =
-                        (pkg.splitFlags[i] & ApplicationInfo.FLAG_HAS_CODE) != 0;
-                if (splitShouldHaveCode && !apkHasCode(pkg.splitCodePaths[i])) {
+                        (pkg.getSplitFlags()[i] & ApplicationInfo.FLAG_HAS_CODE) != 0;
+                if (splitShouldHaveCode && !apkHasCode(pkg.getSplitCodePaths()[i])) {
                     throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
-                            "Package " + pkg.splitCodePaths[i] + " code is missing");
+                            "Package " + pkg.getSplitCodePaths()[i] + " code is missing");
                 }
             }
         }
@@ -11068,118 +11014,59 @@
      * Implementation detail: This method must NOT have any side effect. It would
      * ideally be static, but, it requires locks to read system state.
      */
-    private static void applyPolicy(PackageParser.Package pkg, final @ParseFlags int parseFlags,
-            final @ScanFlags int scanFlags, PackageParser.Package platformPkg) {
+    private static void applyPolicy(ParsedPackage parsedPackage, final @ParseFlags int parseFlags,
+            final @ScanFlags int scanFlags, AndroidPackage platformPkg) {
         if ((scanFlags & SCAN_AS_SYSTEM) != 0) {
-            pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
-            if (pkg.applicationInfo.isDirectBootAware()) {
-                // we're direct boot aware; set for all components
-                for (PackageParser.Service s : pkg.services) {
-                    s.info.directBootAware = true;
-                }
-                for (PackageParser.Provider p : pkg.providers) {
-                    p.info.directBootAware = true;
-                }
-                for (PackageParser.Activity a : pkg.activities) {
-                    a.info.directBootAware = true;
-                }
-                for (PackageParser.Activity r : pkg.receivers) {
-                    r.info.directBootAware = true;
-                }
+            parsedPackage.setSystem(true);
+            // TODO(b/135203078): Can this be done in PackageParser? Or just inferred when the flag
+            //  is set during parse.
+            if (parsedPackage.isDirectBootAware()) {
+                parsedPackage.setAllComponentsDirectBootAware(true);
             }
-            if (compressedFileExists(pkg.codePath)) {
-                pkg.isStub = true;
+            if (compressedFileExists(parsedPackage.getCodePath())) {
+                parsedPackage.setIsStub(true);
             }
         } else {
-            // non system apps can't be flagged as core
-            pkg.coreApp = false;
-            // clear flags not applicable to regular apps
-            pkg.applicationInfo.flags &=
-                    ~ApplicationInfo.FLAG_PERSISTENT;
-            pkg.applicationInfo.privateFlags &=
-                    ~ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE;
-            pkg.applicationInfo.privateFlags &=
-                    ~ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE;
-            // cap permission priorities
-            if (pkg.permissionGroups != null && pkg.permissionGroups.size() > 0) {
-                for (int i = pkg.permissionGroups.size() - 1; i >= 0; --i) {
-                    pkg.permissionGroups.get(i).info.priority = 0;
-                }
-            }
+            parsedPackage
+                    // non system apps can't be flagged as core
+                    .setCoreApp(false)
+                    // clear flags not applicable to regular apps
+                    .setPersistent(false)
+                    .setDefaultToDeviceProtectedStorage(false)
+                    .setDirectBootAware(false)
+                    // non system apps can't have permission priority
+                    .capPermissionPriorities();
         }
         if ((scanFlags & SCAN_AS_PRIVILEGED) == 0) {
-            // clear protected broadcasts
-            pkg.protectedBroadcasts = null;
-            // ignore export request for single user receivers
-            if (pkg.receivers != null) {
-                for (int i = pkg.receivers.size() - 1; i >= 0; --i) {
-                    final PackageParser.Activity receiver = pkg.receivers.get(i);
-                    if ((receiver.info.flags & ActivityInfo.FLAG_SINGLE_USER) != 0) {
-                        receiver.info.exported = false;
-                    }
-                }
-            }
-            // ignore export request for single user services
-            if (pkg.services != null) {
-                for (int i = pkg.services.size() - 1; i >= 0; --i) {
-                    final PackageParser.Service service = pkg.services.get(i);
-                    if ((service.info.flags & ServiceInfo.FLAG_SINGLE_USER) != 0) {
-                        service.info.exported = false;
-                    }
-                }
-            }
-            // ignore export request for single user providers
-            if (pkg.providers != null) {
-                for (int i = pkg.providers.size() - 1; i >= 0; --i) {
-                    final PackageParser.Provider provider = pkg.providers.get(i);
-                    if ((provider.info.flags & ProviderInfo.FLAG_SINGLE_USER) != 0) {
-                        provider.info.exported = false;
-                    }
-                }
-            }
+            parsedPackage
+                    .clearProtectedBroadcasts()
+                    .markNotActivitiesAsNotExportedIfSingleUser();
         }
 
-        if ((scanFlags & SCAN_AS_PRIVILEGED) != 0) {
-            pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
-        }
-
-        if ((scanFlags & SCAN_AS_OEM) != 0) {
-            pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_OEM;
-        }
-
-        if ((scanFlags & SCAN_AS_VENDOR) != 0) {
-            pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_VENDOR;
-        }
-
-        if ((scanFlags & SCAN_AS_PRODUCT) != 0) {
-            pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_PRODUCT;
-        }
-
-        if ((scanFlags & SCAN_AS_SYSTEM_EXT) != 0) {
-            pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT;
-        }
-
-        if ((scanFlags & SCAN_AS_ODM) != 0) {
-            pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_ODM;
-        }
+        parsedPackage.setPrivileged((scanFlags & SCAN_AS_PRIVILEGED) != 0)
+                .setOem((scanFlags & SCAN_AS_OEM) != 0)
+                .setVendor((scanFlags & SCAN_AS_VENDOR) != 0)
+                .setProduct((scanFlags & SCAN_AS_PRODUCT) != 0)
+                .setSystemExt((scanFlags & SCAN_AS_SYSTEM_EXT) != 0)
+                .setOdm((scanFlags & SCAN_AS_ODM) != 0);
 
         // Check if the package is signed with the same key as the platform package.
-        if (PLATFORM_PACKAGE_NAME.equals(pkg.packageName) ||
-                (platformPkg != null && compareSignatures(
-                        platformPkg.mSigningDetails.signatures,
-                        pkg.mSigningDetails.signatures) == PackageManager.SIGNATURE_MATCH)) {
-            pkg.applicationInfo.privateFlags |=
-                ApplicationInfo.PRIVATE_FLAG_SIGNED_WITH_PLATFORM_KEY;
-        }
+        parsedPackage.setSignedWithPlatformKey(
+                (PLATFORM_PACKAGE_NAME.equals(parsedPackage.getPackageName())
+                        || (platformPkg != null && compareSignatures(
+                        platformPkg.getSigningDetails().signatures,
+                        parsedPackage.getSigningDetails().signatures
+                ) == PackageManager.SIGNATURE_MATCH))
+        );
 
-        if (!isSystemApp(pkg)) {
+        if (!isSystemApp(parsedPackage)) {
             // Only system apps can use these features.
-            pkg.mOriginalPackages = null;
-            pkg.mRealPackage = null;
-            pkg.mAdoptPermissions = null;
+            parsedPackage.clearOriginalPackages()
+                    .setRealPackage(null)
+                    .clearAdoptPermissions();
         }
 
-        PackageBackwardCompatibility.modifySharedLibraries(pkg);
+        PackageBackwardCompatibility.modifySharedLibraries(parsedPackage);
     }
 
     private static @NonNull <T> T assertNotNull(@Nullable T object, String message)
@@ -11199,15 +11086,15 @@
      *
      * @throws PackageManagerException If the package fails any of the validation checks
      */
-    private void assertPackageIsValid(PackageParser.Package pkg, final @ParseFlags int parseFlags,
+    private void assertPackageIsValid(AndroidPackage pkg, final @ParseFlags int parseFlags,
             final @ScanFlags int scanFlags)
                     throws PackageManagerException {
         if ((parseFlags & PackageParser.PARSE_ENFORCE_CODE) != 0) {
             assertCodePolicy(pkg);
         }
 
-        if (pkg.applicationInfo.getCodePath() == null ||
-                pkg.applicationInfo.getResourcePath() == null) {
+        if (pkg.getAppInfoCodePath() == null ||
+                pkg.getAppInfoResourcePath() == null) {
             // Bail out. The resource and code paths haven't been set.
             throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
                     "Code and resource paths haven't been set correctly");
@@ -11218,9 +11105,10 @@
         final boolean isUserInstall = (scanFlags & SCAN_BOOTING) == 0;
         final boolean isFirstBootOrUpgrade = (scanFlags & SCAN_FIRST_BOOT_OR_UPGRADE) != 0;
         if ((isUserInstall || isFirstBootOrUpgrade)
-                && mApexManager.isApexPackage(pkg.packageName)) {
+                && mApexManager.isApexPackage(pkg.getPackageName())) {
             throw new PackageManagerException(INSTALL_FAILED_DUPLICATE_PACKAGE,
-                    pkg.packageName + " is an APEX package and can't be installed as an APK.");
+                    pkg.getPackageName()
+                            + " is an APEX package and can't be installed as an APK.");
         }
 
         // Make sure we're not adding any bogus keyset info
@@ -11229,11 +11117,11 @@
 
         synchronized (mLock) {
             // The special "android" package can only be defined once
-            if (pkg.packageName.equals("android")) {
+            if (pkg.getPackageName().equals("android")) {
                 if (mAndroidApplication != null) {
                     Slog.w(TAG, "*************************************************");
                     Slog.w(TAG, "Core android package being redefined.  Skipping.");
-                    Slog.w(TAG, " codePath=" + pkg.codePath);
+                    Slog.w(TAG, " codePath=" + pkg.getCodePath());
                     Slog.w(TAG, "*************************************************");
                     throw new PackageManagerException(INSTALL_FAILED_DUPLICATE_PACKAGE,
                             "Core android package being redefined.  Skipping.");
@@ -11241,23 +11129,24 @@
             }
 
             // A package name must be unique; don't allow duplicates
-            if ((scanFlags & SCAN_NEW_INSTALL) == 0 && mPackages.containsKey(pkg.packageName)) {
+            if ((scanFlags & SCAN_NEW_INSTALL) == 0
+                    && mPackages.containsKey(pkg.getPackageName())) {
                 throw new PackageManagerException(INSTALL_FAILED_DUPLICATE_PACKAGE,
-                        "Application package " + pkg.packageName
+                        "Application package " + pkg.getPackageName()
                         + " already installed.  Skipping duplicate.");
             }
 
-            if (pkg.applicationInfo.isStaticSharedLibrary()) {
+            if (pkg.isStaticSharedLibrary()) {
                 // Static libs have a synthetic package name containing the version
                 // but we still want the base name to be unique.
                 if ((scanFlags & SCAN_NEW_INSTALL) == 0
-                        && mPackages.containsKey(pkg.manifestPackageName)) {
+                        && mPackages.containsKey(pkg.getManifestPackageName())) {
                     throw new PackageManagerException(
                             "Duplicate static shared lib provider package");
                 }
 
                 // Static shared libraries should have at least O target SDK
-                if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.O) {
+                if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.O) {
                     throw new PackageManagerException(
                             "Packages declaring static-shared libs must target O SDK or higher");
                 }
@@ -11270,73 +11159,67 @@
 
                 // Package declaring static a shared lib cannot be renamed since the package
                 // name is synthetic and apps can't code around package manager internals.
-                if (!ArrayUtils.isEmpty(pkg.mOriginalPackages)) {
+                if (!ArrayUtils.isEmpty(pkg.getOriginalPackages())) {
                     throw new PackageManagerException(
                             "Packages declaring static-shared libs cannot be renamed");
                 }
 
-                // Package declaring static a shared lib cannot declare child packages
-                if (!ArrayUtils.isEmpty(pkg.childPackages)) {
-                    throw new PackageManagerException(
-                            "Packages declaring static-shared libs cannot have child packages");
-                }
-
                 // Package declaring static a shared lib cannot declare dynamic libs
-                if (!ArrayUtils.isEmpty(pkg.libraryNames)) {
+                if (!ArrayUtils.isEmpty(pkg.getLibraryNames())) {
                     throw new PackageManagerException(
                             "Packages declaring static-shared libs cannot declare dynamic libs");
                 }
 
                 // Package declaring static a shared lib cannot declare shared users
-                if (pkg.mSharedUserId != null) {
+                if (pkg.getSharedUserId() != null) {
                     throw new PackageManagerException(
                             "Packages declaring static-shared libs cannot declare shared users");
                 }
 
                 // Static shared libs cannot declare activities
-                if (!pkg.activities.isEmpty()) {
+                if (pkg.getActivities() != null && !pkg.getActivities().isEmpty()) {
                     throw new PackageManagerException(
                             "Static shared libs cannot declare activities");
                 }
 
                 // Static shared libs cannot declare services
-                if (!pkg.services.isEmpty()) {
+                if (pkg.getServices() != null && !pkg.getServices().isEmpty()) {
                     throw new PackageManagerException(
                             "Static shared libs cannot declare services");
                 }
 
                 // Static shared libs cannot declare providers
-                if (!pkg.providers.isEmpty()) {
+                if (pkg.getProviders() != null && !pkg.getProviders().isEmpty()) {
                     throw new PackageManagerException(
                             "Static shared libs cannot declare content providers");
                 }
 
                 // Static shared libs cannot declare receivers
-                if (!pkg.receivers.isEmpty()) {
+                if (pkg.getReceivers() != null && !pkg.getReceivers().isEmpty()) {
                     throw new PackageManagerException(
                             "Static shared libs cannot declare broadcast receivers");
                 }
 
                 // Static shared libs cannot declare permission groups
-                if (!pkg.permissionGroups.isEmpty()) {
+                if (pkg.getPermissionGroups() != null && !pkg.getPermissionGroups().isEmpty()) {
                     throw new PackageManagerException(
                             "Static shared libs cannot declare permission groups");
                 }
 
                 // Static shared libs cannot declare permissions
-                if (!pkg.permissions.isEmpty()) {
+                if (pkg.getPermissions() != null && !pkg.getPermissions().isEmpty()) {
                     throw new PackageManagerException(
                             "Static shared libs cannot declare permissions");
                 }
 
                 // Static shared libs cannot declare protected broadcasts
-                if (pkg.protectedBroadcasts != null) {
+                if (pkg.getProtectedBroadcasts() != null) {
                     throw new PackageManagerException(
                             "Static shared libs cannot declare protected broadcasts");
                 }
 
                 // Static shared libs cannot be overlay targets
-                if (pkg.mOverlayTarget != null) {
+                if (pkg.getOverlayTarget() != null) {
                     throw new PackageManagerException(
                             "Static shared libs cannot be overlay targets");
                 }
@@ -11346,16 +11229,17 @@
                 long maxVersionCode = Long.MAX_VALUE;
 
                 LongSparseArray<SharedLibraryInfo> versionedLib = mSharedLibraries.get(
-                        pkg.staticSharedLibName);
+                        pkg.getStaticSharedLibName());
                 if (versionedLib != null) {
                     final int versionCount = versionedLib.size();
                     for (int i = 0; i < versionCount; i++) {
                         SharedLibraryInfo libInfo = versionedLib.valueAt(i);
                         final long libVersionCode = libInfo.getDeclaringPackage()
                                 .getLongVersionCode();
-                        if (libInfo.getLongVersion() <  pkg.staticSharedLibVersion) {
+                        if (libInfo.getLongVersion() < pkg.getStaticSharedLibVersion()) {
                             minVersionCode = Math.max(minVersionCode, libVersionCode + 1);
-                        } else if (libInfo.getLongVersion() >  pkg.staticSharedLibVersion) {
+                        } else if (libInfo.getLongVersion()
+                                > pkg.getStaticSharedLibVersion()) {
                             maxVersionCode = Math.min(maxVersionCode, libVersionCode - 1);
                         } else {
                             minVersionCode = maxVersionCode = libVersionCode;
@@ -11370,23 +11254,6 @@
                 }
             }
 
-            // Only privileged apps and updated privileged apps can add child packages.
-            if (pkg.childPackages != null && !pkg.childPackages.isEmpty()) {
-                if ((scanFlags & SCAN_AS_PRIVILEGED) == 0) {
-                    throw new PackageManagerException("Only privileged apps can add child "
-                            + "packages. Ignoring package " + pkg.packageName);
-                }
-                final int childCount = pkg.childPackages.size();
-                for (int i = 0; i < childCount; i++) {
-                    PackageParser.Package childPkg = pkg.childPackages.get(i);
-                    if (mSettings.hasOtherDisabledSystemPkgWithChildLPr(pkg.packageName,
-                            childPkg.packageName)) {
-                        throw new PackageManagerException("Can't override child of "
-                                + "another disabled app. Ignoring package " + pkg.packageName);
-                    }
-                }
-            }
-
             // If we're only installing presumed-existing packages, require that the
             // scanned APK is both already known and at the path previously established
             // for it.  Previously unknown packages we pick up normally, but if we have an
@@ -11396,29 +11263,30 @@
             // to the user-installed location. If we don't allow this change, any newer,
             // user-installed version of the application will be ignored.
             if ((scanFlags & SCAN_REQUIRE_KNOWN) != 0) {
-                if (mExpectingBetter.containsKey(pkg.packageName)) {
+                if (mExpectingBetter.containsKey(pkg.getPackageName())) {
                     logCriticalInfo(Log.WARN,
-                            "Relax SCAN_REQUIRE_KNOWN requirement for package " + pkg.packageName);
+                            "Relax SCAN_REQUIRE_KNOWN requirement for package "
+                                    + pkg.getPackageName());
                 } else {
-                    PackageSetting known = mSettings.getPackageLPr(pkg.packageName);
+                    PackageSetting known = mSettings.getPackageLPr(pkg.getPackageName());
                     if (known != null) {
                         if (DEBUG_PACKAGE_SCANNING) {
-                            Log.d(TAG, "Examining " + pkg.codePath
+                            Log.d(TAG, "Examining " + pkg.getCodePath()
                                     + " and requiring known paths " + known.codePathString
                                     + " & " + known.resourcePathString);
                         }
-                        if (!pkg.applicationInfo.getCodePath().equals(known.codePathString)
-                                || !pkg.applicationInfo.getResourcePath().equals(
+                        if (!pkg.getAppInfoCodePath().equals(known.codePathString)
+                                || !pkg.getAppInfoResourcePath().equals(
                                         known.resourcePathString)) {
                             throw new PackageManagerException(INSTALL_FAILED_PACKAGE_CHANGED,
-                                    "Application package " + pkg.packageName
-                                    + " found at " + pkg.applicationInfo.getCodePath()
+                                    "Application package " + pkg.getPackageName()
+                                    + " found at " + pkg.getAppInfoCodePath()
                                     + " but expected at " + known.codePathString
                                     + "; ignoring.");
                         }
                     } else {
                         throw new PackageManagerException(INSTALL_FAILED_INVALID_INSTALL_LOCATION,
-                                "Application package " + pkg.packageName
+                                "Application package " + pkg.getPackageName()
                                 + " not found; ignoring.");
                     }
                 }
@@ -11433,11 +11301,13 @@
             }
 
             // Verify that packages sharing a user with a privileged app are marked as privileged.
-            if (!pkg.isPrivileged() && (pkg.mSharedUserId != null)) {
+            if (!pkg.isPrivileged() && (pkg.getSharedUserId() != null)) {
                 SharedUserSetting sharedUserSetting = null;
                 try {
-                    sharedUserSetting = mSettings.getSharedUserLPw(pkg.mSharedUserId, 0, 0, false);
-                } catch (PackageManagerException ignore) {}
+                    sharedUserSetting = mSettings.getSharedUserLPw(pkg.getSharedUserId(),
+                            0, 0, false);
+                } catch (PackageManagerException ignore) {
+                }
                 if (sharedUserSetting != null && sharedUserSetting.isPrivileged()) {
                     // Exempt SharedUsers signed with the platform key.
                     PackageSetting platformPkgSetting = mSettings.mPackages.get("android");
@@ -11445,18 +11315,18 @@
                             != PackageParser.SigningDetails.UNKNOWN)
                             && (compareSignatures(
                                     platformPkgSetting.signatures.mSigningDetails.signatures,
-                                    pkg.mSigningDetails.signatures)
+                            pkg.getSigningDetails().signatures)
                                             != PackageManager.SIGNATURE_MATCH)) {
                         throw new PackageManagerException("Apps that share a user with a " +
                                 "privileged app must themselves be marked as privileged. " +
-                                pkg.packageName + " shares privileged user " +
-                                pkg.mSharedUserId + ".");
+                                pkg.getPackageName() + " shares privileged user " +
+                                pkg.getSharedUserId() + ".");
                     }
                 }
             }
 
             // Apply policies specific for runtime resource overlays (RROs).
-            if (pkg.mOverlayTarget != null) {
+            if (pkg.getOverlayTarget() != null) {
                 // System overlays have some restrictions on their use of the 'static' state.
                 if ((scanFlags & SCAN_AS_SYSTEM) != 0) {
                     // We are scanning a system overlay. This can be the first scan of the
@@ -11464,54 +11334,62 @@
                     if ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) {
                         // This must be an update to a system overlay.
                         final PackageSetting previousPkg = assertNotNull(
-                                mSettings.getPackageLPr(pkg.packageName),
+                                mSettings.getPackageLPr(pkg.getPackageName()),
                                 "previous package state not present");
 
                         // previousPkg.pkg may be null: the package will be not be scanned if the
                         // package manager knows there is a newer version on /data.
                         // TODO[b/79435695]: Find a better way to keep track of the "static"
                         // property for RROs instead of having to parse packages on /system
-                        PackageParser.Package ppkg = previousPkg.pkg;
+                        AndroidPackage ppkg = previousPkg.pkg;
                         if (ppkg == null) {
                             try {
                                 final PackageParser pp = new PackageParser();
-                                ppkg = pp.parsePackage(previousPkg.codePath,
-                                        parseFlags | PackageParser.PARSE_IS_SYSTEM_DIR);
+                                // TODO(b/135203078): Do we really need to parse here? Maybe use
+                                //  a shortened path?
+                                ppkg = pp.parseParsedPackage(previousPkg.codePath,
+                                        parseFlags | PackageParser.PARSE_IS_SYSTEM_DIR,
+                                        false)
+                                        .hideAsFinal();
                             } catch (PackageParserException e) {
                                 Slog.w(TAG, "failed to parse " + previousPkg.codePath, e);
                             }
                         }
 
                         // Static overlays cannot be updated.
-                        if (ppkg != null && ppkg.mOverlayIsStatic) {
-                            throw new PackageManagerException("Overlay " + pkg.packageName +
-                                    " is static and cannot be upgraded.");
+                        if (ppkg != null && ppkg.isOverlayIsStatic()) {
+                            throw new PackageManagerException("Overlay "
+                                    + pkg.getPackageName()
+                                    + " is static and cannot be upgraded.");
                         // Non-static overlays cannot be converted to static overlays.
-                        } else if (pkg.mOverlayIsStatic) {
-                            throw new PackageManagerException("Overlay " + pkg.packageName +
-                                    " cannot be upgraded into a static overlay.");
+                        } else if (pkg.isOverlayIsStatic()) {
+                            throw new PackageManagerException("Overlay "
+                                    + pkg.getPackageName()
+                                    + " cannot be upgraded into a static overlay.");
                         }
                     }
                 } else {
                     // The overlay is a non-system overlay. Non-system overlays cannot be static.
-                    if (pkg.mOverlayIsStatic) {
-                        throw new PackageManagerException("Overlay " + pkg.packageName +
-                                " is static but not pre-installed.");
+                    if (pkg.isOverlayIsStatic()) {
+                        throw new PackageManagerException("Overlay "
+                                + pkg.getPackageName()
+                                + " is static but not pre-installed.");
                     }
 
                     // A non-preloaded overlay packages must have targetSdkVersion >= Q, or be
                     // signed with the platform certificate. Check this in increasing order of
                     // computational cost.
-                    if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.Q) {
+                    if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.Q) {
                         final PackageSetting platformPkgSetting =
                                 mSettings.getPackageLPr("android");
                         if ((platformPkgSetting.signatures.mSigningDetails
                                     != PackageParser.SigningDetails.UNKNOWN)
                                 && (compareSignatures(
                                         platformPkgSetting.signatures.mSigningDetails.signatures,
-                                        pkg.mSigningDetails.signatures)
+                                pkg.getSigningDetails().signatures)
                                     != PackageManager.SIGNATURE_MATCH)) {
-                            throw new PackageManagerException("Overlay " + pkg.packageName
+                            throw new PackageManagerException("Overlay "
+                                    + pkg.getPackageName()
                                     + " must target Q or later, "
                                     + "or be signed with the platform certificate");
                         }
@@ -11521,18 +11399,19 @@
                     // only be used if it is signed with the same certificate as its target. If the
                     // target is already installed, check this here to augment the last line of
                     // defence which is OMS.
-                    if (pkg.mOverlayTargetName == null) {
+                    if (pkg.getOverlayTargetName() == null) {
                         final PackageSetting targetPkgSetting =
-                                mSettings.getPackageLPr(pkg.mOverlayTarget);
+                                mSettings.getPackageLPr(pkg.getOverlayTarget());
                         if (targetPkgSetting != null) {
                             if ((targetPkgSetting.signatures.mSigningDetails
                                         != PackageParser.SigningDetails.UNKNOWN)
                                     && (compareSignatures(
                                             targetPkgSetting.signatures.mSigningDetails.signatures,
-                                            pkg.mSigningDetails.signatures)
+                                    pkg.getSigningDetails().signatures)
                                         != PackageManager.SIGNATURE_MATCH)) {
-                                throw new PackageManagerException("Overlay " + pkg.packageName
-                                        + " and target " + pkg.mOverlayTarget + " signed with"
+                                throw new PackageManagerException("Overlay "
+                                        + pkg.getPackageName() + " and target "
+                                        + pkg.getOverlayTarget() + " signed with"
                                         + " different certificates, and the overlay lacks"
                                         + " <overlay android:targetName>");
                             }
@@ -11612,71 +11491,67 @@
      * Adds a scanned package to the system. When this method is finished, the package will
      * be available for query, resolution, etc...
      */
-    private void commitPackageSettings(PackageParser.Package pkg,
-            @Nullable PackageParser.Package oldPkg, PackageSetting pkgSetting,
+    private void commitPackageSettings(AndroidPackage pkg,
+            @Nullable AndroidPackage oldPkg, PackageSetting pkgSetting,
             final @ScanFlags int scanFlags, boolean chatty, ReconciledPackage reconciledPkg) {
-        final String pkgName = pkg.packageName;
+        final String pkgName = pkg.getPackageName();
         if (mCustomResolverComponentName != null &&
-                mCustomResolverComponentName.getPackageName().equals(pkg.packageName)) {
+                mCustomResolverComponentName.getPackageName().equals(pkg.getPackageName())) {
             setUpCustomResolverActivity(pkg);
         }
 
-        if (pkg.packageName.equals("android")) {
+        if (pkg.getPackageName().equals("android")) {
             synchronized (mLock) {
-                if ((scanFlags & SCAN_CHECK_ONLY) == 0) {
-                    // Set up information for our fall-back user intent resolution activity.
-                    mPlatformPackage = pkg;
-                    pkg.mVersionCode = mSdkVersion;
-                    pkg.mVersionCodeMajor = 0;
-                    mAndroidApplication = pkg.applicationInfo;
-                    if (!mResolverReplaced) {
-                        mResolveActivity.applicationInfo = mAndroidApplication;
-                        mResolveActivity.name = ResolverActivity.class.getName();
-                        mResolveActivity.packageName = mAndroidApplication.packageName;
-                        mResolveActivity.processName = "system:ui";
-                        mResolveActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
-                        mResolveActivity.documentLaunchMode = ActivityInfo.DOCUMENT_LAUNCH_NEVER;
-                        mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
-                        mResolveActivity.theme = R.style.Theme_Material_Dialog_Alert;
-                        mResolveActivity.exported = true;
-                        mResolveActivity.enabled = true;
-                        mResolveActivity.resizeMode = ActivityInfo.RESIZE_MODE_RESIZEABLE;
-                        mResolveActivity.configChanges = ActivityInfo.CONFIG_SCREEN_SIZE
-                                | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE
-                                | ActivityInfo.CONFIG_SCREEN_LAYOUT
-                                | ActivityInfo.CONFIG_ORIENTATION
-                                | ActivityInfo.CONFIG_KEYBOARD
-                                | ActivityInfo.CONFIG_KEYBOARD_HIDDEN;
-                        mResolveInfo.activityInfo = mResolveActivity;
-                        mResolveInfo.priority = 0;
-                        mResolveInfo.preferredOrder = 0;
-                        mResolveInfo.match = 0;
-                        mResolveComponentName = new ComponentName(
-                                mAndroidApplication.packageName, mResolveActivity.name);
-                    }
+                // Set up information for our fall-back user intent resolution activity.
+                mPlatformPackage = pkg;
+                mAndroidApplication = pkg.toAppInfo();
+                if (!mResolverReplaced) {
+                    mResolveActivity.applicationInfo = mAndroidApplication;
+                    mResolveActivity.name = ResolverActivity.class.getName();
+                    mResolveActivity.packageName = mAndroidApplication.packageName;
+                    mResolveActivity.processName = "system:ui";
+                    mResolveActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
+                    mResolveActivity.documentLaunchMode = ActivityInfo.DOCUMENT_LAUNCH_NEVER;
+                    mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
+                    mResolveActivity.theme = R.style.Theme_Material_Dialog_Alert;
+                    mResolveActivity.exported = true;
+                    mResolveActivity.enabled = true;
+                    mResolveActivity.resizeMode = ActivityInfo.RESIZE_MODE_RESIZEABLE;
+                    mResolveActivity.configChanges = ActivityInfo.CONFIG_SCREEN_SIZE
+                            | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE
+                            | ActivityInfo.CONFIG_SCREEN_LAYOUT
+                            | ActivityInfo.CONFIG_ORIENTATION
+                            | ActivityInfo.CONFIG_KEYBOARD
+                            | ActivityInfo.CONFIG_KEYBOARD_HIDDEN;
+                    mResolveInfo.activityInfo = mResolveActivity;
+                    mResolveInfo.priority = 0;
+                    mResolveInfo.preferredOrder = 0;
+                    mResolveInfo.match = 0;
+                    mResolveComponentName = new ComponentName(
+                            mAndroidApplication.packageName, mResolveActivity.name);
                 }
             }
         }
 
-        ArrayList<PackageParser.Package> clientLibPkgs = null;
+        ArrayList<AndroidPackage> clientLibPkgs = null;
         // writer
         synchronized (mLock) {
             if (!ArrayUtils.isEmpty(reconciledPkg.allowedSharedLibraryInfos)) {
                 for (SharedLibraryInfo info : reconciledPkg.allowedSharedLibraryInfos) {
                     commitSharedLibraryInfoLocked(info);
                 }
-                final Map<String, PackageParser.Package> combinedPackages =
-                        reconciledPkg.getCombinedPackages();
+                final Map<String, AndroidPackage> combinedSigningDetails =
+                        reconciledPkg.getCombinedAvailablePackages();
                 try {
                     // Shared libraries for the package need to be updated.
-                    updateSharedLibrariesLocked(pkg, null, combinedPackages);
+                    updateSharedLibrariesLocked(pkg, null, combinedSigningDetails);
                 } catch (PackageManagerException e) {
                     Slog.e(TAG, "updateSharedLibrariesLPr failed: ", e);
                 }
                 // Update all applications that use this library. Skip when booting
                 // since this will be done after all packages are scaned.
                 if ((scanFlags & SCAN_BOOTING) == 0) {
-                    clientLibPkgs = updateAllSharedLibrariesLocked(pkg, combinedPackages);
+                    clientLibPkgs = updateAllSharedLibrariesLocked(pkg, combinedSigningDetails);
                 }
             }
         }
@@ -11700,9 +11575,9 @@
         // Also need to kill any apps that are dependent on the library.
         if (clientLibPkgs != null) {
             for (int i=0; i<clientLibPkgs.size(); i++) {
-                PackageParser.Package clientPkg = clientLibPkgs.get(i);
-                killApplication(clientPkg.applicationInfo.packageName,
-                        clientPkg.applicationInfo.uid, "update lib");
+                AndroidPackage clientPkg = clientLibPkgs.get(i);
+                killApplication(clientPkg.getAppInfoPackageName(),
+                        clientPkg.getUid(), "update lib");
             }
         }
 
@@ -11715,7 +11590,7 @@
             // Add the new setting to mSettings
             mSettings.insertPackageSettingLPw(pkgSetting, pkg);
             // Add the new setting to mPackages
-            mPackages.put(pkg.applicationInfo.packageName, pkg);
+            mPackages.put(pkg.getAppInfoPackageName(), pkg);
 
             // Add the package's KeySets to the global KeySetManagerService
             KeySetManagerService ksms = mSettings.mKeySetManagerService;
@@ -11726,7 +11601,7 @@
 
             // Don't allow ephemeral applications to define new permissions groups.
             if ((scanFlags & SCAN_AS_INSTANT_APP) != 0) {
-                Slog.w(TAG, "Permission groups from package " + pkg.packageName
+                Slog.w(TAG, "Permission groups from package " + pkg.getPackageName()
                         + " ignored: instant apps cannot define new permission groups.");
             } else {
                 mPermissionManager.addAllPermissionGroups(pkg, chatty);
@@ -11734,31 +11609,31 @@
 
             // Don't allow ephemeral applications to define new permissions.
             if ((scanFlags & SCAN_AS_INSTANT_APP) != 0) {
-                Slog.w(TAG, "Permissions from package " + pkg.packageName
+                Slog.w(TAG, "Permissions from package " + pkg.getPackageName()
                         + " ignored: instant apps cannot define new permissions.");
             } else {
                 mPermissionManager.addAllPermissions(pkg, chatty);
             }
 
-            int collectionSize = pkg.instrumentation.size();
+            int collectionSize = ArrayUtils.size(pkg.getInstrumentations());
             StringBuilder r = null;
             int i;
             for (i = 0; i < collectionSize; i++) {
-                PackageParser.Instrumentation a = pkg.instrumentation.get(i);
-                a.info.packageName = pkg.applicationInfo.packageName;
-                a.info.sourceDir = pkg.applicationInfo.sourceDir;
-                a.info.publicSourceDir = pkg.applicationInfo.publicSourceDir;
-                a.info.splitNames = pkg.splitNames;
-                a.info.splitSourceDirs = pkg.applicationInfo.splitSourceDirs;
-                a.info.splitPublicSourceDirs = pkg.applicationInfo.splitPublicSourceDirs;
-                a.info.splitDependencies = pkg.applicationInfo.splitDependencies;
-                a.info.dataDir = pkg.applicationInfo.dataDir;
-                a.info.deviceProtectedDataDir = pkg.applicationInfo.deviceProtectedDataDir;
-                a.info.credentialProtectedDataDir = pkg.applicationInfo.credentialProtectedDataDir;
-                a.info.primaryCpuAbi = pkg.applicationInfo.primaryCpuAbi;
-                a.info.secondaryCpuAbi = pkg.applicationInfo.secondaryCpuAbi;
-                a.info.nativeLibraryDir = pkg.applicationInfo.nativeLibraryDir;
-                a.info.secondaryNativeLibraryDir = pkg.applicationInfo.secondaryNativeLibraryDir;
+                ParsedInstrumentation a = pkg.getInstrumentations().get(i);
+                a.setPackageName(pkg.getAppInfoPackageName());
+                a.sourceDir = pkg.getBaseCodePath();
+                a.publicSourceDir = pkg.getPublicSourceDir();
+                a.splitNames = pkg.getSplitNames();
+                a.splitSourceDirs = pkg.getSplitCodePaths();
+                a.splitPublicSourceDirs = pkg.getSplitPublicSourceDirs();
+                a.splitDependencies = pkg.getSplitDependencies();
+                a.dataDir = pkg.getDataDir();
+                a.deviceProtectedDataDir = pkg.getDeviceProtectedDataDir();
+                a.credentialProtectedDataDir = pkg.getCredentialProtectedDataDir();
+                a.primaryCpuAbi = pkg.getPrimaryCpuAbi();
+                a.secondaryCpuAbi = pkg.getSecondaryCpuAbi();
+                a.nativeLibraryDir = pkg.getNativeLibraryDir();
+                a.secondaryNativeLibraryDir = pkg.getSecondaryNativeLibraryDir();
                 mInstrumentation.put(a.getComponentName(), a);
                 if (chatty) {
                     if (r == null) {
@@ -11766,19 +11641,16 @@
                     } else {
                         r.append(' ');
                     }
-                    r.append(a.info.name);
+                    r.append(a.getName());
                 }
             }
             if (r != null) {
                 if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, "  Instrumentation: " + r);
             }
 
-            if (pkg.protectedBroadcasts != null) {
-                collectionSize = pkg.protectedBroadcasts.size();
+            if (pkg.getProtectedBroadcasts() != null) {
                 synchronized (mProtectedBroadcasts) {
-                    for (i = 0; i < collectionSize; i++) {
-                        mProtectedBroadcasts.add(pkg.protectedBroadcasts.get(i));
-                    }
+                    mProtectedBroadcasts.addAll(pkg.getProtectedBroadcasts());
                 }
             }
 
@@ -11802,14 +11674,14 @@
         Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
     }
 
-    private void setUpCustomResolverActivity(PackageParser.Package pkg) {
+    private void setUpCustomResolverActivity(AndroidPackage pkg) {
         synchronized (mLock) {
             mResolverReplaced = true;
             // Set up information for custom user intent resolution activity.
-            mResolveActivity.applicationInfo = pkg.applicationInfo;
+            mResolveActivity.applicationInfo = pkg.toAppInfo();
             mResolveActivity.name = mCustomResolverComponentName.getClassName();
-            mResolveActivity.packageName = pkg.applicationInfo.packageName;
-            mResolveActivity.processName = pkg.applicationInfo.packageName;
+            mResolveActivity.packageName = pkg.getAppInfoPackageName();
+            mResolveActivity.processName = pkg.getAppInfoProcessName();
             mResolveActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
             mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS |
                     ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS;
@@ -11876,22 +11748,13 @@
         }
     }
 
-    private void removePackageLI(PackageParser.Package pkg, boolean chatty) {
+    private void removePackageLI(AndroidPackage pkg, boolean chatty) {
         // Remove the parent package setting
-        PackageSetting ps = (PackageSetting) pkg.mExtras;
+        PackageSetting ps = getPackageSetting(pkg.getPackageName());
         if (ps != null) {
             removePackageLI(ps.name, chatty);
         } else if (DEBUG_REMOVE && chatty) {
-            Log.d(TAG, "Not removing package " + pkg.packageName + "; mExtras == null");
-        }
-        // Remove the child package setting
-        final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
-        for (int i = 0; i < childCount; i++) {
-            PackageParser.Package childPkg = pkg.childPackages.get(i);
-            ps = (PackageSetting) childPkg.mExtras;
-            if (ps != null) {
-                removePackageLI(ps.name, chatty);
-            }
+            Log.d(TAG, "Not removing package " + pkg.getPackageName() + "; mExtras == null");
         }
     }
 
@@ -11903,7 +11766,7 @@
 
         // writer
         synchronized (mLock) {
-            final PackageParser.Package removedPackage = mPackages.remove(packageName);
+            final AndroidPackage removedPackage = mPackages.remove(packageName);
             if (removedPackage != null) {
                 cleanPackageDataStructuresLILPw(removedPackage, chatty);
             }
@@ -11916,11 +11779,11 @@
                 mInjector.getUserManagerInternal().getUserIds(), mSettings.mPackages);
         mPermissionManager.removeAllPermissions(pkg, chatty);
 
-        final int instrumentationSize = pkg.instrumentation.size();
+        final int instrumentationSize = ArrayUtils.size(pkg.getInstrumentations());
         StringBuilder r = null;
         int i;
         for (i = 0; i < instrumentationSize; i++) {
-            PackageParser.Instrumentation a = pkg.instrumentation.get(i);
+            ParsedInstrumentation a = pkg.getInstrumentations().get(i);
             mInstrumentation.remove(a.getComponentName());
             if (DEBUG_REMOVE && chatty) {
                 if (r == null) {
@@ -11928,7 +11791,7 @@
                 } else {
                     r.append(' ');
                 }
-                r.append(a.info.name);
+                r.append(a.getName());
             }
         }
         if (r != null) {
@@ -11936,12 +11799,12 @@
         }
 
         r = null;
-        if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
+        if ((pkg.getFlags() & ApplicationInfo.FLAG_SYSTEM) != 0) {
             // Only system apps can hold shared libraries.
-            if (pkg.libraryNames != null) {
-                final int libraryNamesSize = pkg.libraryNames.size();
+            if (pkg.getLibraryNames() != null) {
+                final int libraryNamesSize = pkg.getLibraryNames().size();
                 for (i = 0; i < libraryNamesSize; i++) {
-                    String name = pkg.libraryNames.get(i);
+                    String name = pkg.getLibraryNames().get(i);
                     if (removeSharedLibraryLPw(name, 0)) {
                         if (DEBUG_REMOVE && chatty) {
                             if (r == null) {
@@ -11959,15 +11822,16 @@
         r = null;
 
         // Any package can hold static shared libraries.
-        if (pkg.staticSharedLibName != null) {
-            if (removeSharedLibraryLPw(pkg.staticSharedLibName, pkg.staticSharedLibVersion)) {
+        if (pkg.getStaticSharedLibName() != null) {
+            if (removeSharedLibraryLPw(pkg.getStaticSharedLibName(),
+                    pkg.getStaticSharedLibVersion())) {
                 if (DEBUG_REMOVE && chatty) {
                     if (r == null) {
                         r = new StringBuilder(256);
                     } else {
                         r.append(' ');
                     }
-                    r.append(pkg.staticSharedLibName);
+                    r.append(pkg.getStaticSharedLibName());
                 }
             }
         }
@@ -12308,11 +12172,11 @@
                 // Cannot hide static shared libs as they are considered
                 // a part of the using app (emulating static linking). Also
                 // static libs are installed always on internal storage.
-                PackageParser.Package pkg = mPackages.get(packageName);
-                if (pkg != null && pkg.staticSharedLibName != null) {
+                AndroidPackage pkg = mPackages.get(packageName);
+                if (pkg != null && pkg.getStaticSharedLibName() != null) {
                     Slog.w(TAG, "Cannot hide package: " + packageName
                             + " providing static shared library: "
-                            + pkg.staticSharedLibName);
+                            + pkg.getStaticSharedLibName());
                     return false;
                 }
                 // Only allow protected packages to hide themselves.
@@ -12358,17 +12222,17 @@
             if (pkgSetting == null || !pkgSetting.isSystem()) {
                 return;
             }
-            PackageParser.Package pkg = pkgSetting.pkg;
-            if (pkg != null && pkg.applicationInfo != null) {
-                pkg.applicationInfo.hiddenUntilInstalled = hidden;
+            AndroidPackage pkg = pkgSetting.pkg;
+            if (pkg != null) {
+                pkg.mutate().setHiddenUntilInstalled(hidden);
             }
             final PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(packageName);
             if (disabledPs == null) {
                 return;
             }
             pkg = disabledPs.pkg;
-            if (pkg != null && pkg.applicationInfo != null) {
-                pkg.applicationInfo.hiddenUntilInstalled = hidden;
+            if (pkg != null) {
+                pkg.mutate().setHiddenUntilInstalled(hidden);
             }
         }
     }
@@ -12560,7 +12424,7 @@
             if (installed) {
                 if ((installFlags & PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS)
                         != 0 && pkgSetting.pkg != null) {
-                    whiteListedPermissions = pkgSetting.pkg.requestedPermissions;
+                    whiteListedPermissions = pkgSetting.pkg.getRequestedPermissions();
                 }
                 mPermissionManager.setWhitelistedRestrictedPermissions(packageName,
                         whiteListedPermissions, FLAG_PERMISSION_WHITELIST_INSTALLER, userId);
@@ -12990,11 +12854,11 @@
                     // Cannot suspend static shared libs as they are considered
                     // a part of the using app (emulating static linking). Also
                     // static libs are installed always on internal storage.
-                    PackageParser.Package pkg = mPackages.get(packageName);
-                    if (pkg != null && pkg.applicationInfo.isStaticSharedLibrary()) {
+                    AndroidPackage pkg = mPackages.get(packageName);
+                    if (pkg != null && pkg.isStaticSharedLibrary()) {
                         Slog.w(TAG, "Cannot suspend package: " + packageName
                                 + " providing static shared library: "
-                                + pkg.staticSharedLibName);
+                                + pkg.getStaticSharedLibName());
                         continue;
                     }
                 }
@@ -13139,10 +13003,10 @@
 
     private int getUidForVerifier(VerifierInfo verifierInfo) {
         synchronized (mLock) {
-            final PackageParser.Package pkg = mPackages.get(verifierInfo.packageName);
+            final AndroidPackage pkg = mPackages.get(verifierInfo.packageName);
             if (pkg == null) {
                 return -1;
-            } else if (pkg.mSigningDetails.signatures.length != 1) {
+            } else if (pkg.getSigningDetails().signatures.length != 1) {
                 Slog.i(TAG, "Verifier package " + verifierInfo.packageName
                         + " has more than one signature; ignoring");
                 return -1;
@@ -13156,7 +13020,7 @@
 
             final byte[] expectedPublicKey;
             try {
-                final Signature verifierSig = pkg.mSigningDetails.signatures[0];
+                final Signature verifierSig = pkg.getSigningDetails().signatures[0];
                 final PublicKey publicKey = verifierSig.getPublicKey();
                 expectedPublicKey = publicKey.getEncoded();
             } catch (CertificateException e) {
@@ -13171,7 +13035,7 @@
                 return -1;
             }
 
-            return pkg.applicationInfo.uid;
+            return pkg.getUid();
         }
     }
 
@@ -13347,26 +13211,33 @@
         final int callingUid = Binder.getCallingUid();
         final int callingUserId = UserHandle.getUserId(callingUid);
         synchronized (mLock) {
-            PackageParser.Package pkg = mPackages.get(packageName);
-            if (pkg == null || pkg.activities == null) {
+            AndroidPackage pkg = mPackages.get(packageName);
+            if (pkg == null || ArrayUtils.isEmpty(pkg.getActivities())) {
                 return ParceledListSlice.emptyList();
             }
-            if (pkg.mExtras == null) {
+            final PackageSetting ps = getPackageSetting(pkg.getPackageName());
+            if (ps == null) {
                 return ParceledListSlice.emptyList();
             }
-            final PackageSetting ps = (PackageSetting) pkg.mExtras;
             if (shouldFilterApplicationLocked(ps, callingUid, callingUserId)) {
                 return ParceledListSlice.emptyList();
             }
-            final int count = pkg.activities.size();
+            final int count = ArrayUtils.size(pkg.getActivities());
             ArrayList<IntentFilter> result = new ArrayList<>();
             for (int n=0; n<count; n++) {
-                PackageParser.Activity activity = pkg.activities.get(n);
+                ParsedActivity activity = pkg.getActivities().get(n);
                 if (activity.intents != null && activity.intents.size() > 0) {
                     result.addAll(activity.intents);
                 }
             }
-            return new ParceledListSlice<>(result);
+            return new ParceledListSlice<IntentFilter>(result) {
+                @Override
+                protected void writeElement(IntentFilter parcelable, Parcel dest, int callFlags) {
+                    // IntentFilter has final Parcelable methods, so redirect to the subclass
+                    ((ParsedActivityIntentInfo) parcelable).writeIntentInfoToParcel(dest,
+                            callFlags);
+                }
+            };
         }
     }
 
@@ -13549,7 +13420,7 @@
         // package has not opted out of backup participation.
         final boolean update = res.removedInfo != null
                 && res.removedInfo.removedPackage != null;
-        final int flags = (res.pkg == null) ? 0 : res.pkg.applicationInfo.flags;
+        final int flags = (res.pkg == null) ? 0 : res.pkg.getFlags();
         boolean doRestore = !update
                 && ((flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0);
 
@@ -13587,7 +13458,7 @@
                 try {
                     if (bm.isBackupServiceActive(userId)) {
                         bm.restoreAtInstallForUser(
-                                userId, res.pkg.applicationInfo.packageName, token);
+                                userId, res.pkg.getAppInfoPackageName(), token);
                     } else {
                         doRestore = false;
                     }
@@ -13612,8 +13483,8 @@
             IRollbackManager rm = IRollbackManager.Stub.asInterface(
                     ServiceManager.getService(Context.ROLLBACK_SERVICE));
 
-            final String packageName = res.pkg.applicationInfo.packageName;
-            final String seInfo = res.pkg.applicationInfo.seInfo;
+            final String packageName = res.pkg.getAppInfoPackageName();
+            final String seInfo = res.pkg.getSeInfo();
             final int[] allUsers = mUserManager.getUserIds();
             final int[] installedUsers;
 
@@ -13682,7 +13553,7 @@
                 if (data.res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
                     continue;
                 }
-                if (packageName.equals(data.res.pkg.applicationInfo.packageName)) {
+                if (packageName.equals(data.res.pkg.getAppInfoPackageName())) {
                     // right package; but is it for the right user?
                     for (int uIndex = 0; uIndex < data.res.newUsers.length; uIndex++) {
                         if (userId == data.res.newUsers[uIndex]) {
@@ -14025,12 +13896,12 @@
             synchronized (mLock) {
                 // Currently installed package which the new package is attempting to replace or
                 // null if no such package is installed.
-                PackageParser.Package installedPkg = mPackages.get(packageName);
+                AndroidPackage installedPkg = mPackages.get(packageName);
                 // Package which currently owns the data which the new package will own if installed.
                 // If an app is unstalled while keeping data (e.g., adb uninstall -k), installedPkg
                 // will be null whereas dataOwnerPkg will contain information about the package
                 // which was uninstalled while keeping its data.
-                PackageParser.Package dataOwnerPkg = installedPkg;
+                AndroidPackage dataOwnerPkg = installedPkg;
                 if (dataOwnerPkg  == null) {
                     PackageSetting ps = mSettings.mPackages.get(packageName);
                     if (ps != null) {
@@ -14057,7 +13928,7 @@
 
                 if (dataOwnerPkg != null) {
                     if (!PackageManagerServiceUtils.isDowngradePermitted(installFlags,
-                            dataOwnerPkg.applicationInfo.flags)) {
+                            dataOwnerPkg.getFlags())) {
                         try {
                             checkDowngrade(dataOwnerPkg, pkgLite);
                         } catch (PackageManagerException e) {
@@ -14070,7 +13941,7 @@
                 if (installedPkg != null) {
                     if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
                         // Check for updated system application.
-                        if ((installedPkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+                        if ((installedPkg.getFlags() & ApplicationInfo.FLAG_SYSTEM) != 0) {
                             return PackageHelper.RECOMMEND_INSTALL_INTERNAL;
                         } else {
                             // If current upgrade specifies particular preference
@@ -14543,7 +14414,7 @@
          * Rename package into final resting place. All paths on the given
          * scanned package should be updated to reflect the rename.
          */
-        abstract boolean doRename(int status, PackageParser.Package pkg);
+        abstract boolean doRename(int status, ParsedPackage parsedPackage);
         abstract int doPostInstall(int status, int uid);
 
         /** @see PackageSettingBase#codePathString */
@@ -14687,7 +14558,8 @@
             return status;
         }
 
-        boolean doRename(int status, PackageParser.Package pkg) {
+        @Override
+        boolean doRename(int status, ParsedPackage parsedPackage) {
             if (status != PackageManager.INSTALL_SUCCEEDED) {
                 cleanUp();
                 return false;
@@ -14695,7 +14567,7 @@
 
             final File targetDir = codeFile.getParentFile();
             final File beforeCodeFile = codeFile;
-            final File afterCodeFile = getNextCodePath(targetDir, pkg.packageName);
+            final File afterCodeFile = getNextCodePath(targetDir, parsedPackage.getPackageName());
 
             if (DEBUG_INSTALL) Slog.d(TAG, "Renaming " + beforeCodeFile + " to " + afterCodeFile);
             final boolean onIncremental = mIncrementalManager != null
@@ -14723,24 +14595,23 @@
 
             // Reflect the rename in scanned details
             try {
-                pkg.setCodePath(afterCodeFile.getCanonicalPath());
+                parsedPackage.setCodePath(afterCodeFile.getCanonicalPath());
             } catch (IOException e) {
                 Slog.e(TAG, "Failed to get path: " + afterCodeFile, e);
                 return false;
             }
-            pkg.setBaseCodePath(FileUtils.rewriteAfterRename(beforeCodeFile,
-                    afterCodeFile, pkg.baseCodePath));
-            pkg.setSplitCodePaths(FileUtils.rewriteAfterRename(beforeCodeFile,
-                    afterCodeFile, pkg.splitCodePaths));
+            parsedPackage.setBaseCodePath(FileUtils.rewriteAfterRename(beforeCodeFile,
+                    afterCodeFile, parsedPackage.getBaseCodePath()));
+            parsedPackage.setSplitCodePaths(FileUtils.rewriteAfterRename(beforeCodeFile,
+                    afterCodeFile, parsedPackage.getSplitCodePaths()));
 
             // Reflect the rename in app info
-            pkg.setApplicationVolumeUuid(pkg.volumeUuid);
-            pkg.setApplicationInfoCodePath(pkg.codePath);
-            pkg.setApplicationInfoBaseCodePath(pkg.baseCodePath);
-            pkg.setApplicationInfoSplitCodePaths(pkg.splitCodePaths);
-            pkg.setApplicationInfoResourcePath(pkg.codePath);
-            pkg.setApplicationInfoBaseResourcePath(pkg.baseCodePath);
-            pkg.setApplicationInfoSplitResourcePaths(pkg.splitCodePaths);
+            // TODO(b/135203078): Remove all of these application info calls
+            parsedPackage.setApplicationVolumeUuid(parsedPackage.getVolumeUuid())
+                    .setApplicationInfoCodePath(parsedPackage.getCodePath())
+                    .setApplicationInfoResourcePath(parsedPackage.getCodePath())
+                    .setApplicationInfoBaseResourcePath(parsedPackage.getBaseCodePath())
+                    .setApplicationInfoSplitResourcePaths(parsedPackage.getSplitCodePaths());
 
             return true;
         }
@@ -14843,20 +14714,20 @@
             return status;
         }
 
-        boolean doRename(int status, PackageParser.Package pkg) {
+        @Override
+        boolean doRename(int status, ParsedPackage parsedPackage) {
             if (status != PackageManager.INSTALL_SUCCEEDED) {
                 cleanUp(move.toUuid);
                 return false;
             }
 
             // Reflect the move in app info
-            pkg.setApplicationVolumeUuid(pkg.volumeUuid);
-            pkg.setApplicationInfoCodePath(pkg.codePath);
-            pkg.setApplicationInfoBaseCodePath(pkg.baseCodePath);
-            pkg.setApplicationInfoSplitCodePaths(pkg.splitCodePaths);
-            pkg.setApplicationInfoResourcePath(pkg.codePath);
-            pkg.setApplicationInfoBaseResourcePath(pkg.baseCodePath);
-            pkg.setApplicationInfoSplitResourcePaths(pkg.splitCodePaths);
+            // TODO(b/135203078): Remove all of these application info calls
+            parsedPackage.setApplicationVolumeUuid(parsedPackage.getVolumeUuid())
+                    .setApplicationInfoCodePath(parsedPackage.getCodePath())
+                    .setApplicationInfoResourcePath(parsedPackage.getCodePath())
+                    .setApplicationInfoBaseResourcePath(parsedPackage.getBaseCodePath())
+                    .setApplicationInfoSplitResourcePaths(parsedPackage.getSplitCodePaths());
 
             return true;
         }
@@ -14932,14 +14803,14 @@
         int[] origUsers;
         // The set of users that now have this package installed.
         int[] newUsers;
-        PackageParser.Package pkg;
+        AndroidPackage pkg;
         int returnCode;
         String returnMsg;
         String installerPackageName;
         PackageRemovedInfo removedInfo;
         ArrayMap<String, PackageInstalledInfo> addedChildPackages;
         // The set of packages consuming this shared library or null if no consumers exist.
-        ArrayList<PackageParser.Package> libraryConsumers;
+        ArrayList<AndroidPackage> libraryConsumers;
 
         public void setError(int code, String msg) {
             setReturnCode(code);
@@ -14995,66 +14866,15 @@
         }
     }
 
-    /**
-     * Checks whether the parent or any of the child packages have a change shared
-     * user. For a package to be a valid update the shred users of the parent and
-     * the children should match. We may later support changing child shared users.
-     * @param oldPkg The updated package.
-     * @param newPkg The update package.
-     * @return The shared user that change between the versions.
-     */
-    private String getParentOrChildPackageChangedSharedUser(PackageParser.Package oldPkg,
-            PackageParser.Package newPkg) {
-        // Check parent shared user
-        if (!Objects.equals(oldPkg.mSharedUserId, newPkg.mSharedUserId)) {
-            return newPkg.packageName;
-        }
-        // Check child shared users
-        final int oldChildCount = (oldPkg.childPackages != null) ? oldPkg.childPackages.size() : 0;
-        final int newChildCount = (newPkg.childPackages != null) ? newPkg.childPackages.size() : 0;
-        for (int i = 0; i < newChildCount; i++) {
-            PackageParser.Package newChildPkg = newPkg.childPackages.get(i);
-            // If this child was present, did it have the same shared user?
-            for (int j = 0; j < oldChildCount; j++) {
-                PackageParser.Package oldChildPkg = oldPkg.childPackages.get(j);
-                if (newChildPkg.packageName.equals(oldChildPkg.packageName)
-                        && !Objects.equals(newChildPkg.mSharedUserId, oldChildPkg.mSharedUserId)) {
-                    return newChildPkg.packageName;
-                }
-            }
-        }
-        return null;
-    }
-
     private void removeNativeBinariesLI(PackageSetting ps) {
-        // Remove the lib path for the parent package
         if (ps != null) {
             NativeLibraryHelper.removeNativeBinariesLI(ps.legacyNativeLibraryPathString);
-            // Remove the lib path for the child packages
-            final int childCount = (ps.childPackageNames != null) ? ps.childPackageNames.size() : 0;
-            for (int i = 0; i < childCount; i++) {
-                PackageSetting childPs = null;
-                synchronized (mLock) {
-                    childPs = mSettings.getPackageLPr(ps.childPackageNames.get(i));
-                }
-                if (childPs != null) {
-                    NativeLibraryHelper.removeNativeBinariesLI(childPs
-                            .legacyNativeLibraryPathString);
-                }
-            }
         }
     }
 
     @GuardedBy("mLock")
-    private void enableSystemPackageLPw(PackageParser.Package pkg) {
-        // Enable the parent package
-        mSettings.enableSystemPackageLPw(pkg.packageName);
-        // Enable the child packages
-        final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
-        for (int i = 0; i < childCount; i++) {
-            PackageParser.Package childPkg = pkg.childPackages.get(i);
-            mSettings.enableSystemPackageLPw(childPkg.packageName);
-        }
+    private void enableSystemPackageLPw(AndroidPackage pkg) {
+        mSettings.enableSystemPackageLPw(pkg.getPackageName());
     }
 
     @GuardedBy("mLock")
@@ -15095,7 +14915,7 @@
         final int[] installedForUsers = res.origUsers;
         final int installReason = installArgs.installReason;
 
-        if (DEBUG_INSTALL) Slog.d(TAG, "New package installed in " + pkg.codePath);
+        if (DEBUG_INSTALL) Slog.d(TAG, "New package installed in " + pkg.getCodePath());
         synchronized (mLock) {
 // NOTE: This changes slightly to include UPDATE_PERMISSIONS_ALL regardless of the size of pkg.permissions
             mPermissionManager.updatePermissions(pkgName, pkg);
@@ -15168,7 +14988,7 @@
                 mSettings.writeKernelMappingLPr(ps);
             }
             res.name = pkgName;
-            res.uid = pkg.applicationInfo.uid;
+            res.uid = pkg.getUid();
             res.pkg = pkg;
             mSettings.setInstallerPackageName(pkgName, installerPackageName);
             res.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
@@ -15226,7 +15046,7 @@
     private static class ReconcileRequest {
         public final Map<String, ScanResult> scannedPackages;
 
-        public final Map<String, PackageParser.Package> allPackages;
+        public final Map<String, AndroidPackage> allPackages;
         public final Map<String, LongSparseArray<SharedLibraryInfo>> sharedLibrarySource;
         public final Map<String, InstallArgs> installArgs;
         public final Map<String, PackageInstalledInfo> installResults;
@@ -15239,7 +15059,7 @@
                 Map<String, PackageInstalledInfo> installResults,
                 Map<String, PrepareResult> preparedPackages,
                 Map<String, LongSparseArray<SharedLibraryInfo>> sharedLibrarySource,
-                Map<String, PackageParser.Package> allPackages,
+                Map<String, AndroidPackage> allPackages,
                 Map<String, VersionInfo> versionInfos,
                 Map<String, PackageSetting> lastStaticSharedLibSettings) {
             this.scannedPackages = scannedPackages;
@@ -15254,7 +15074,7 @@
 
         private ReconcileRequest(Map<String, ScanResult> scannedPackages,
                 Map<String, LongSparseArray<SharedLibraryInfo>> sharedLibrarySource,
-                Map<String, PackageParser.Package> allPackages,
+                Map<String, AndroidPackage> allPackages,
                 Map<String, VersionInfo> versionInfos,
                 Map<String, PackageSetting> lastStaticSharedLibSettings) {
             this(scannedPackages, Collections.emptyMap(), Collections.emptyMap(),
@@ -15322,15 +15142,17 @@
          * with the package(s) currently being installed. The to-be installed packages take
          * precedence and may shadow already installed packages.
          */
-        private Map<String, PackageParser.Package> getCombinedPackages() {
-            final ArrayMap<String, PackageParser.Package> combinedPackages =
+        private Map<String, AndroidPackage> getCombinedAvailablePackages() {
+            final ArrayMap<String, AndroidPackage> combined =
                     new ArrayMap<>(request.allPackages.size() + request.scannedPackages.size());
 
-            combinedPackages.putAll(request.allPackages);
+            combined.putAll(request.allPackages);
+
             for (ScanResult scanResult : request.scannedPackages.values()) {
-                combinedPackages.put(scanResult.pkgSetting.name, scanResult.request.pkg);
+                combined.put(scanResult.pkgSetting.name, scanResult.request.parsedPackage);
             }
-            return combinedPackages;
+
+            return combined;
         }
     }
 
@@ -15343,8 +15165,9 @@
         final Map<String, ReconciledPackage> result = new ArrayMap<>(scannedPackages.size());
 
         // make a copy of the existing set of packages so we can combine them with incoming packages
-        final ArrayMap<String, PackageParser.Package> combinedPackages =
+        final ArrayMap<String, AndroidPackage> combinedPackages =
                 new ArrayMap<>(request.allPackages.size() + scannedPackages.size());
+
         combinedPackages.putAll(request.allPackages);
 
         final Map<String, LongSparseArray<SharedLibraryInfo>> incomingSharedLibraries =
@@ -15354,7 +15177,7 @@
             final ScanResult scanResult = scannedPackages.get(installPackageName);
 
             // add / replace existing with incoming packages
-            combinedPackages.put(scanResult.pkgSetting.name, scanResult.request.pkg);
+            combinedPackages.put(scanResult.pkgSetting.name, scanResult.request.parsedPackage);
 
             // in the first pass, we'll build up the set of incoming shared libraries
             final List<SharedLibraryInfo> allowedSharedLibInfos =
@@ -15387,7 +15210,7 @@
                         | (killApp ? 0 : PackageManager.DELETE_DONT_KILL_APP);
                 deletePackageAction = mayDeletePackageLocked(res.removedInfo,
                         prepareResult.originalPs, prepareResult.disabledPs,
-                        prepareResult.childPackageSettings, deleteFlags, null /* all users */);
+                        deleteFlags, null /* all users */);
                 if (deletePackageAction == null) {
                     throw new ReconcileFailure(
                             PackageManager.INSTALL_FAILED_REPLACE_COULDNT_DELETE,
@@ -15399,7 +15222,7 @@
 
             final int scanFlags = scanResult.request.scanFlags;
             final int parseFlags = scanResult.request.parseFlags;
-            final PackageParser.Package pkg = scanResult.request.pkg;
+            final ParsedPackage parsedPackage = scanResult.request.parsedPackage;
 
             final PackageSetting disabledPkgSetting = scanResult.request.disabledPkgSetting;
             final PackageSetting lastStaticSharedLibSetting =
@@ -15412,35 +15235,37 @@
             boolean sharedUserSignaturesChanged = false;
             SigningDetails signingDetails = null;
             if (ksms.shouldCheckUpgradeKeySetLocked(signatureCheckPs, scanFlags)) {
-                if (ksms.checkUpgradeKeySetLocked(signatureCheckPs, pkg)) {
+                if (ksms.checkUpgradeKeySetLocked(signatureCheckPs, parsedPackage)) {
                     // We just determined the app is signed correctly, so bring
                     // over the latest parsed certs.
                 } else {
                     if ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) {
                         throw new ReconcileFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
-                                "Package " + pkg.packageName + " upgrade keys do not match the "
-                                        + "previously installed version");
+                                "Package " + parsedPackage.getPackageName()
+                                        + " upgrade keys do not match the previously installed"
+                                        + " version");
                     } else {
-                        String msg = "System package " + pkg.packageName
+                        String msg = "System package " + parsedPackage.getPackageName()
                                 + " signature changed; retaining data.";
                         reportSettingsProblem(Log.WARN, msg);
                     }
                 }
-                signingDetails = pkg.mSigningDetails;
+                signingDetails = parsedPackage.getSigningDetails();
             } else {
                 try {
                     final VersionInfo versionInfo = request.versionInfos.get(installPackageName);
                     final boolean compareCompat = isCompatSignatureUpdateNeeded(versionInfo);
                     final boolean compareRecover = isRecoverSignatureUpdateNeeded(versionInfo);
                     final boolean compatMatch = verifySignatures(signatureCheckPs,
-                            disabledPkgSetting, pkg.mSigningDetails, compareCompat, compareRecover);
+                            disabledPkgSetting, parsedPackage.getSigningDetails(), compareCompat,
+                            compareRecover);
                     // The new KeySets will be re-added later in the scanning process.
                     if (compatMatch) {
                         removeAppKeySetData = true;
                     }
                     // We just determined the app is signed correctly, so bring
                     // over the latest parsed certs.
-                    signingDetails = pkg.mSigningDetails;
+                    signingDetails = parsedPackage.getSigningDetails();
 
 
                     // if this is is a sharedUser, check to see if the new package is signed by a
@@ -15448,10 +15273,10 @@
                     // signing certificate than the existing one, and if so, copy over the new
                     // details
                     if (signatureCheckPs.sharedUser != null) {
-                        if (pkg.mSigningDetails.hasAncestor(
+                        if (parsedPackage.getSigningDetails().hasAncestor(
                                 signatureCheckPs.sharedUser.signatures.mSigningDetails)) {
                             signatureCheckPs.sharedUser.signatures.mSigningDetails =
-                                    pkg.mSigningDetails;
+                                    parsedPackage.getSigningDetails();
                         }
                         if (signatureCheckPs.sharedUser.signaturesChanged == null) {
                             signatureCheckPs.sharedUser.signaturesChanged = Boolean.FALSE;
@@ -15461,7 +15286,7 @@
                     if ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) {
                         throw new ReconcileFailure(e);
                     }
-                    signingDetails = pkg.mSigningDetails;
+                    signingDetails = parsedPackage.getSigningDetails();
 
                     // If the system app is part of a shared user we allow that shared user to
                     // change
@@ -15476,7 +15301,7 @@
                                 signatureCheckPs.sharedUser.signatures.mSigningDetails.signatures;
                         if (signatureCheckPs.sharedUser.signaturesChanged != null
                                 && compareSignatures(sharedUserSignatures,
-                                        pkg.mSigningDetails.signatures)
+                                parsedPackage.getSigningDetails().signatures)
                                         != PackageManager.SIGNATURE_MATCH) {
                             if (SystemProperties.getInt("ro.product.first_api_level", 0) <= 29) {
                                 // Mismatched signatures is an error and silently skipping system
@@ -15496,18 +15321,19 @@
                                 // whichever package happened to be scanned later.
                                 throw new IllegalStateException(
                                         "Signature mismatch on system package "
-                                                + pkg.packageName + " for shared user "
+                                                + parsedPackage.getPackageName()
+                                                + " for shared user "
                                                 + scanResult.pkgSetting.sharedUser);
                             }
                         }
 
                         sharedUserSignaturesChanged = true;
                         signatureCheckPs.sharedUser.signatures.mSigningDetails =
-                                pkg.mSigningDetails;
+                                parsedPackage.getSigningDetails();
                         signatureCheckPs.sharedUser.signaturesChanged = Boolean.TRUE;
                     }
                     // File a report about this.
-                    String msg = "System package " + pkg.packageName
+                    String msg = "System package " + parsedPackage.getPackageName()
                             + " signature changed; retaining data.";
                     reportSettingsProblem(Log.WARN, msg);
                 } catch (IllegalArgumentException e) {
@@ -15541,8 +15367,9 @@
             }
             try {
                 result.get(installPackageName).collectedSharedLibraryInfos =
-                        collectSharedLibraryInfos(scanResult.request.pkg, combinedPackages,
-                                request.sharedLibrarySource, incomingSharedLibraries);
+                        collectSharedLibraryInfos(scanResult.request.parsedPackage,
+                                combinedPackages, request.sharedLibrarySource,
+                                incomingSharedLibraries);
 
             } catch (PackageManagerException e) {
                 throw new ReconcileFailure(e.error, e.getMessage());
@@ -15560,7 +15387,7 @@
             ScanResult scanResult,
             Map<String, LongSparseArray<SharedLibraryInfo>> existingSharedLibraries) {
         // Let's used the parsed package as scanResult.pkgSetting may be null
-        final PackageParser.Package pkg = scanResult.request.pkg;
+        final ParsedPackage parsedPackage = scanResult.request.parsedPackage;
         if (scanResult.staticSharedLibraryInfo == null
                 && scanResult.dynamicSharedLibraryInfos == null) {
             return null;
@@ -15571,12 +15398,12 @@
             return Collections.singletonList(scanResult.staticSharedLibraryInfo);
         }
         final boolean hasDynamicLibraries =
-                (pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0
+                (parsedPackage.getFlags() & ApplicationInfo.FLAG_SYSTEM) != 0
                         && scanResult.dynamicSharedLibraryInfos != null;
         if (!hasDynamicLibraries) {
             return null;
         }
-        final boolean isUpdatedSystemApp = pkg.isUpdatedSystemApp();
+        final boolean isUpdatedSystemApp = parsedPackage.isUpdatedSystemApp();
         // We may not yet have disabled the updated package yet, so be sure to grab the
         // current setting if that's the case.
         final PackageSetting updatedSystemPs = isUpdatedSystemApp
@@ -15585,9 +15412,9 @@
                         : scanResult.request.disabledPkgSetting
                 : null;
         if (isUpdatedSystemApp && (updatedSystemPs.pkg == null
-                || updatedSystemPs.pkg.libraryNames == null)) {
-            Slog.w(TAG, "Package " + pkg.packageName + " declares libraries that are not "
-                    + "declared on the system image; skipping");
+                || updatedSystemPs.pkg.getLibraryNames() == null)) {
+            Slog.w(TAG, "Package " + parsedPackage.getPackageName()
+                    + " declares libraries that are not declared on the system image; skipping");
             return null;
         }
         final ArrayList<SharedLibraryInfo> infos =
@@ -15605,16 +15432,17 @@
                 // with it.  Better to just have the restriction here, be
                 // conservative, and create many fewer cases that can negatively
                 // impact the user experience.
-                if (!updatedSystemPs.pkg.libraryNames.contains(name)) {
-                    Slog.w(TAG, "Package " + pkg.packageName + " declares library " + name
+                if (!updatedSystemPs.pkg.getLibraryNames().contains(name)) {
+                    Slog.w(TAG, "Package " + parsedPackage.getPackageName()
+                            + " declares library " + name
                             + " that is not declared on system image; skipping");
                     continue;
                 }
             }
             if (sharedLibExists(
                     name, SharedLibraryInfo.VERSION_UNDEFINED, existingSharedLibraries)) {
-                Slog.w(TAG, "Package " + pkg.packageName + " declares library " + name
-                        + " that already exists; skipping");
+                Slog.w(TAG, "Package " + parsedPackage.getPackageName() + " declares library "
+                        + name + " that already exists; skipping");
                 continue;
             }
             infos.add(info);
@@ -15652,68 +15480,38 @@
         for (ReconciledPackage reconciledPkg : request.reconciledPackages.values()) {
             final ScanResult scanResult = reconciledPkg.scanResult;
             final ScanRequest scanRequest = scanResult.request;
-            final PackageParser.Package pkg = scanRequest.pkg;
-            final String packageName = pkg.packageName;
+            final ParsedPackage parsedPackage = scanRequest.parsedPackage;
+            final String packageName = parsedPackage.getPackageName();
             final PackageInstalledInfo res = reconciledPkg.installResult;
 
             if (reconciledPkg.prepareResult.replace) {
-                PackageParser.Package oldPackage = mPackages.get(packageName);
+                AndroidPackage oldPackage = mPackages.get(packageName);
 
                 // Set the update and install times
-                PackageSetting deletedPkgSetting = (PackageSetting) oldPackage.mExtras;
-                setInstallAndUpdateTime(pkg, deletedPkgSetting.firstInstallTime,
-                        System.currentTimeMillis());
+                PackageSetting deletedPkgSetting = getPackageSetting(oldPackage.getPackageName());
+                reconciledPkg.pkgSetting.firstInstallTime = deletedPkgSetting.firstInstallTime;
+                reconciledPkg.pkgSetting.lastUpdateTime = System.currentTimeMillis();
 
                 if (reconciledPkg.prepareResult.system) {
                     // Remove existing system package
                     removePackageLI(oldPackage, true);
-                    if (!disableSystemPackageLPw(oldPackage, pkg)) {
+                    if (!disableSystemPackageLPw(oldPackage)) {
                         // We didn't need to disable the .apk as a current system package,
                         // which means we are replacing another update that is already
                         // installed.  We need to make sure to delete the older one's .apk.
                         res.removedInfo.args = createInstallArgsForExisting(
-                                oldPackage.applicationInfo.getCodePath(),
-                                oldPackage.applicationInfo.getResourcePath(),
-                                getAppDexInstructionSets(oldPackage.applicationInfo));
+                                oldPackage.getAppInfoCodePath(),
+                                oldPackage.getAppInfoResourcePath(),
+                                getAppDexInstructionSets(oldPackage.getPrimaryCpuAbi(),
+                                        oldPackage.getSecondaryCpuAbi()));
                     } else {
                         res.removedInfo.args = null;
                     }
-
-                    // Update the package dynamic state if succeeded
-                    // Now that the install succeeded make sure we remove data
-                    // directories for any child package the update removed.
-                    final int deletedChildCount = (oldPackage.childPackages != null)
-                            ? oldPackage.childPackages.size() : 0;
-                    final int newChildCount = (pkg.childPackages != null)
-                            ? pkg.childPackages.size() : 0;
-                    for (int i = 0; i < deletedChildCount; i++) {
-                        PackageParser.Package deletedChildPkg = oldPackage.childPackages.get(i);
-                        boolean childPackageDeleted = true;
-                        for (int j = 0; j < newChildCount; j++) {
-                            PackageParser.Package newChildPkg = pkg.childPackages.get(j);
-                            if (deletedChildPkg.packageName.equals(newChildPkg.packageName)) {
-                                childPackageDeleted = false;
-                                break;
-                            }
-                        }
-                        if (childPackageDeleted) {
-                            PackageSetting ps1 = mSettings.getDisabledSystemPkgLPr(
-                                    deletedChildPkg.packageName);
-                            if (ps1 != null && res.removedInfo.removedChildPackages != null) {
-                                PackageRemovedInfo removedChildRes = res.removedInfo
-                                        .removedChildPackages.get(deletedChildPkg.packageName);
-                                removePackageDataLIF(ps1, request.mAllUsers, removedChildRes, 0,
-                                        false);
-                                removedChildRes.removedForAllUsers = mPackages.get(ps1.name)
-                                        == null;
-                            }
-                        }
-                    }
                 } else {
                     try {
                         // Settings will be written during the call to updateSettingsLI().
                         executeDeletePackageLIF(reconciledPkg.deletePackageAction, packageName,
-                                true, request.mAllUsers, false, pkg);
+                                true, request.mAllUsers, false, parsedPackage);
                     } catch (SystemDeleteException e) {
                         if (Build.IS_ENG) {
                             throw new RuntimeException("Unexpected failure", e);
@@ -15729,56 +15527,34 @@
                             Slog.i(TAG, "upgrading pkg " + oldPackage
                                     + " is ASEC-hosted -> UNAVAILABLE");
                         }
-                        final int[] uidArray = new int[]{oldPackage.applicationInfo.uid};
+                        final int[] uidArray = new int[]{oldPackage.getUid()};
                         final ArrayList<String> pkgList = new ArrayList<>(1);
-                        pkgList.add(oldPackage.applicationInfo.packageName);
+                        pkgList.add(oldPackage.getAppInfoPackageName());
                         sendResourcesChangedBroadcast(false, true, pkgList, uidArray, null);
                     }
 
                     // Update the in-memory copy of the previous code paths.
                     PackageSetting ps1 = mSettings.mPackages.get(
-                            reconciledPkg.prepareResult.existingPackage.packageName);
+                            reconciledPkg.prepareResult.existingPackage.getPackageName());
                     if ((reconciledPkg.installArgs.installFlags & PackageManager.DONT_KILL_APP)
                             == 0) {
                         if (ps1.mOldCodePaths == null) {
                             ps1.mOldCodePaths = new ArraySet<>();
                         }
-                        Collections.addAll(ps1.mOldCodePaths, oldPackage.baseCodePath);
-                        if (oldPackage.splitCodePaths != null) {
-                            Collections.addAll(ps1.mOldCodePaths, oldPackage.splitCodePaths);
+                        Collections.addAll(ps1.mOldCodePaths, oldPackage.getBaseCodePath());
+                        if (oldPackage.getSplitCodePaths() != null) {
+                            Collections.addAll(ps1.mOldCodePaths, oldPackage.getSplitCodePaths());
                         }
                     } else {
                         ps1.mOldCodePaths = null;
                     }
-                    if (ps1.childPackageNames != null) {
-                        for (int i = ps1.childPackageNames.size() - 1; i >= 0; --i) {
-                            final String childPkgName = ps1.childPackageNames.get(i);
-                            final PackageSetting childPs = mSettings.mPackages.get(childPkgName);
-                            childPs.mOldCodePaths = ps1.mOldCodePaths;
-                        }
-                    }
 
                     if (reconciledPkg.installResult.returnCode
                             == PackageManager.INSTALL_SUCCEEDED) {
-                        PackageSetting ps2 = mSettings.getPackageLPr(pkg.packageName);
+                        PackageSetting ps2 = mSettings.getPackageLPr(
+                                parsedPackage.getPackageName());
                         if (ps2 != null) {
                             res.removedInfo.removedForAllUsers = mPackages.get(ps2.name) == null;
-                            if (res.removedInfo.removedChildPackages != null) {
-                                final int childCount1 = res.removedInfo.removedChildPackages.size();
-                                // Iterate in reverse as we may modify the collection
-                                for (int i = childCount1 - 1; i >= 0; i--) {
-                                    String childPackageName =
-                                            res.removedInfo.removedChildPackages.keyAt(i);
-                                    if (res.addedChildPackages.containsKey(childPackageName)) {
-                                        res.removedInfo.removedChildPackages.removeAt(i);
-                                    } else {
-                                        PackageRemovedInfo childInfo = res.removedInfo
-                                                .removedChildPackages.valueAt(i);
-                                        childInfo.removedForAllUsers = mPackages.get(
-                                                childInfo.removedPackage) == null;
-                                    }
-                                }
-                            }
                         }
                     }
                 }
@@ -15862,33 +15638,31 @@
                 request.installResult.installerPackageName =
                         request.args.installSource.installerPackageName;
 
-                final String packageName = prepareResult.packageToScan.packageName;
+                final String packageName = prepareResult.packageToScan.getPackageName();
                 prepareResults.put(packageName, prepareResult);
                 installResults.put(packageName, request.installResult);
                 installArgs.put(packageName, request.args);
                 try {
-                    final List<ScanResult> scanResults = scanPackageTracedLI(
+                    final ScanResult result = scanPackageTracedLI(
                             prepareResult.packageToScan, prepareResult.parseFlags,
                             prepareResult.scanFlags, System.currentTimeMillis(),
                             request.args.user);
-                    for (ScanResult result : scanResults) {
-                        if (null != preparedScans.put(result.pkgSetting.pkg.packageName, result)) {
-                            request.installResult.setError(
-                                    PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE,
-                                    "Duplicate package " + result.pkgSetting.pkg.packageName
-                                            + " in multi-package install request.");
-                            return;
-                        }
-                        createdAppId.put(packageName, optimisticallyRegisterAppId(result));
-                        versionInfos.put(result.pkgSetting.pkg.packageName,
-                                getSettingsVersionForPackage(result.pkgSetting.pkg));
-                        if (result.staticSharedLibraryInfo != null) {
-                            final PackageSetting sharedLibLatestVersionSetting =
-                                    getSharedLibLatestVersionSetting(result);
-                            if (sharedLibLatestVersionSetting != null) {
-                                lastStaticSharedLibSettings.put(result.pkgSetting.pkg.packageName,
-                                        sharedLibLatestVersionSetting);
-                            }
+                    if (null != preparedScans.put(result.pkgSetting.pkg.getPackageName(), result)) {
+                        request.installResult.setError(
+                                PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE,
+                                "Duplicate package " + result.pkgSetting.pkg.getPackageName()
+                                        + " in multi-package install request.");
+                        return;
+                    }
+                    createdAppId.put(packageName, optimisticallyRegisterAppId(result));
+                    versionInfos.put(result.pkgSetting.pkg.getPackageName(),
+                            getSettingsVersionForPackage(result.pkgSetting.pkg));
+                    if (result.staticSharedLibraryInfo != null) {
+                        final PackageSetting sharedLibLatestVersionSetting =
+                                getSharedLibLatestVersionSetting(result);
+                        if (sharedLibLatestVersionSetting != null) {
+                            lastStaticSharedLibSettings.put(result.pkgSetting.pkg.getPackageName(),
+                                    sharedLibLatestVersionSetting);
                         }
                     }
                 } catch (PackageManagerException e) {
@@ -15931,7 +15705,8 @@
         } finally {
             if (!success) {
                 for (ScanResult result : preparedScans.values()) {
-                    if (createdAppId.getOrDefault(result.request.pkg.packageName, false)) {
+                    if (createdAppId.getOrDefault(result.request.parsedPackage.getPackageName(),
+                            false)) {
                         cleanUpAppIdCreation(result);
                     }
                 }
@@ -15971,8 +15746,8 @@
                         | FLAG_STORAGE_EXTERNAL | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
             }
             if (reconciledPkg.prepareResult.replace) {
-                mDexManager.notifyPackageUpdated(pkg.packageName,
-                        pkg.baseCodePath, pkg.splitCodePaths);
+                mDexManager.notifyPackageUpdated(pkg.getPackageName(),
+                        pkg.getBaseCodePath(), pkg.getSplitCodePaths());
             }
 
             // Prepare the application profiles for the new code paths.
@@ -15986,7 +15761,7 @@
             // Check whether we need to dexopt the app.
             //
             // NOTE: it is IMPORTANT to call dexopt:
-            //   - after doRename which will sync the package data from PackageParser.Package and
+            //   - after doRename which will sync the package data from AndroidPackage and
             //     its corresponding ApplicationInfo.
             //   - after installNewPackageLIF or replacePackageLIF which will update result with the
             //     uid of the application (pkg.applicationInfo.uid).
@@ -16051,14 +15826,13 @@
         public final int scanFlags;
         public final int parseFlags;
         @Nullable /* The original Package if it is being replaced, otherwise {@code null} */
-        public final PackageParser.Package existingPackage;
-        public final PackageParser.Package packageToScan;
+        public final AndroidPackage existingPackage;
+        public final ParsedPackage packageToScan;
         public final boolean clearCodeCache;
         public final boolean system;
         public final PackageFreezer freezer;
         public final PackageSetting originalPs;
         public final PackageSetting disabledPs;
-        public final PackageSetting[] childPackageSettings;
 
         private PrepareResult(boolean replace, int scanFlags,
                 int parseFlags, PackageParser.Package existingPackage,
@@ -16075,7 +15849,6 @@
             this.freezer = freezer;
             this.originalPs = originalPs;
             this.disabledPs = disabledPs;
-            this.childPackageSettings = childPackageSettings;
         }
     }
 
@@ -16154,10 +15927,10 @@
         pp.setCallback(mPackageParserCallback);
 
         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");
-        final PackageParser.Package pkg;
+        ParsedPackage parsedPackage;
         try {
-            pkg = pp.parsePackage(tmpPackageFile, parseFlags);
-            DexMetadataHelper.validatePackageDexMetadata(pkg);
+            parsedPackage = pp.parseParsedPackage(tmpPackageFile, parseFlags, false);
+            DexMetadataHelper.validatePackageDexMetadata(parsedPackage);
         } catch (PackageParserException e) {
             throw new PrepareFailure("Failed parse during installPackageLI", e);
         } finally {
@@ -16166,23 +15939,23 @@
 
         // Instant apps have several additional install-time checks.
         if (instantApp) {
-            if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.O) {
-                Slog.w(TAG,
-                        "Instant app package " + pkg.packageName + " does not target at least O");
+            if (parsedPackage.getTargetSdkVersion() < Build.VERSION_CODES.O) {
+                Slog.w(TAG, "Instant app package " + parsedPackage.getPackageName()
+                                + " does not target at least O");
                 throw new PrepareFailure(INSTALL_FAILED_INSTANT_APP_INVALID,
                         "Instant app package must target at least O");
             }
-            if (pkg.mSharedUserId != null) {
-                Slog.w(TAG, "Instant app package " + pkg.packageName
+            if (parsedPackage.getSharedUserId() != null) {
+                Slog.w(TAG, "Instant app package " + parsedPackage.getPackageName()
                         + " may not declare sharedUserId.");
                 throw new PrepareFailure(INSTALL_FAILED_INSTANT_APP_INVALID,
                         "Instant app package may not declare a sharedUserId");
             }
         }
 
-        if (pkg.applicationInfo.isStaticSharedLibrary()) {
+        if (parsedPackage.isStaticSharedLibrary()) {
             // Static shared libraries have synthetic package names
-            renameStaticSharedLibraryPackage(pkg);
+            renameStaticSharedLibraryPackage(parsedPackage);
 
             // No static shared libs on external storage
             if (onExternal) {
@@ -16223,12 +15996,14 @@
 
         // If package doesn't declare API override, mark that we have an install
         // time CPU ABI override.
-        if (TextUtils.isEmpty(pkg.cpuAbiOverride)) {
-            pkg.cpuAbiOverride = args.abiOverride;
+        // TODO(b/135203078): Isn't this always true because cpuAbiOverride isn't assigned during
+        //  parsing?
+        if (TextUtils.isEmpty(parsedPackage.getCpuAbiOverride())) {
+            parsedPackage.setCpuAbiOverride(args.abiOverride);
         }
 
-        String pkgName = res.name = pkg.packageName;
-        if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_TEST_ONLY) != 0) {
+        String pkgName = res.name = parsedPackage.getPackageName();
+        if ((parsedPackage.getFlags() & ApplicationInfo.FLAG_TEST_ONLY) != 0) {
             if ((installFlags & PackageManager.INSTALL_ALLOW_TEST) == 0) {
                 throw new PrepareFailure(INSTALL_FAILED_TEST_ONLY, "installPackageLI");
             }
@@ -16237,7 +16012,7 @@
         try {
             // either use what we've been given or parse directly from the APK
             if (args.signingDetails != PackageParser.SigningDetails.UNKNOWN) {
-                pkg.setSigningDetails(args.signingDetails);
+                parsedPackage.setSigningDetails(args.signingDetails);
             } else {
                 // TODO(b/136132412): skip for Incremental installation
                 PackageParser.collectCertificates(pkg, false /* skipVerify */);
@@ -16246,9 +16021,9 @@
             throw new PrepareFailure("Failed collect during installPackageLI", e);
         }
 
-        if (instantApp && pkg.mSigningDetails.signatureSchemeVersion
+        if (instantApp && parsedPackage.getSigningDetails().signatureSchemeVersion
                 < SignatureSchemeVersion.SIGNING_BLOCK_V2) {
-            Slog.w(TAG, "Instant app package " + pkg.packageName
+            Slog.w(TAG, "Instant app package " + parsedPackage.getPackageName()
                     + " is not signed with at least APK Signature Scheme v2");
             throw new PrepareFailure(INSTALL_FAILED_INSTANT_APP_INVALID,
                     "Instant app package must be signed with APK Signature Scheme v2 or greater");
@@ -16262,15 +16037,15 @@
             // Check if installing already existing package
             if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
                 String oldName = mSettings.getRenamedPackageLPr(pkgName);
-                if (pkg.mOriginalPackages != null
-                        && pkg.mOriginalPackages.contains(oldName)
+                if (parsedPackage.getOriginalPackages() != null
+                        && parsedPackage.getOriginalPackages().contains(oldName)
                         && mPackages.containsKey(oldName)) {
                     // This package is derived from an original package,
                     // and this device has been updating from that original
                     // name.  We must continue using the original name, so
                     // rename the new package here.
-                    pkg.setPackageName(oldName);
-                    pkgName = pkg.packageName;
+                    parsedPackage.setPackageName(oldName);
+                    pkgName = parsedPackage.getPackageName();
                     replace = true;
                     if (DEBUG_INSTALL) {
                         Slog.d(TAG, "Replacing existing renamed package: oldName="
@@ -16283,43 +16058,27 @@
                     if (DEBUG_INSTALL) Slog.d(TAG, "Replace existing pacakge: " + pkgName);
                 }
 
-                // Child packages are installed through the parent package
-                if (pkg.parentPackage != null) {
-                    throw new PrepareFailure(
-                            PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
-                            "Package " + pkg.packageName + " is child of package "
-                                    + pkg.parentPackage.parentPackage + ". Child packages "
-                                    + "can be updated only through the parent package.");
-                }
-
                 if (replace) {
                     // Prevent apps opting out from runtime permissions
-                    PackageParser.Package oldPackage = mPackages.get(pkgName);
-                    final int oldTargetSdk = oldPackage.applicationInfo.targetSdkVersion;
-                    final int newTargetSdk = pkg.applicationInfo.targetSdkVersion;
+                    AndroidPackage oldPackage = mPackages.get(pkgName);
+                    final int oldTargetSdk = oldPackage.getTargetSdkVersion();
+                    final int newTargetSdk = parsedPackage.getTargetSdkVersion();
                     if (oldTargetSdk > Build.VERSION_CODES.LOLLIPOP_MR1
                             && newTargetSdk <= Build.VERSION_CODES.LOLLIPOP_MR1) {
                         throw new PrepareFailure(
                                 PackageManager.INSTALL_FAILED_PERMISSION_MODEL_DOWNGRADE,
-                                "Package " + pkg.packageName + " new target SDK " + newTargetSdk
+                                "Package " + parsedPackage.getPackageName()
+                                        + " new target SDK " + newTargetSdk
                                         + " doesn't support runtime permissions but the old"
                                         + " target SDK " + oldTargetSdk + " does.");
                     }
                     // Prevent persistent apps from being updated
-                    if (((oldPackage.applicationInfo.flags & ApplicationInfo.FLAG_PERSISTENT) != 0)
+                    if (((oldPackage.getFlags() & ApplicationInfo.FLAG_PERSISTENT) != 0)
                             && ((installFlags & PackageManager.INSTALL_STAGED) == 0)) {
                         throw new PrepareFailure(PackageManager.INSTALL_FAILED_INVALID_APK,
-                                "Package " + oldPackage.packageName + " is a persistent app. "
+                                "Package " + oldPackage.getPackageName() + " is a persistent app. "
                                         + "Persistent apps are not updateable.");
                     }
-                    // Prevent installing of child packages
-                    if (oldPackage.parentPackage != null) {
-                        throw new PrepareFailure(
-                                PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
-                                "Package " + pkg.packageName + " is child of package "
-                                        + oldPackage.parentPackage + ". Child packages "
-                                        + "can be updated only through the parent package.");
-                    }
                 }
             }
 
@@ -16332,8 +16091,8 @@
                 // of the same package, therefore we need to compare signatures against
                 // the package setting for the latest library version.
                 PackageSetting signatureCheckPs = ps;
-                if (pkg.applicationInfo.isStaticSharedLibrary()) {
-                    SharedLibraryInfo libraryInfo = getLatestSharedLibraVersionLPr(pkg);
+                if (parsedPackage.isStaticSharedLibrary()) {
+                    SharedLibraryInfo libraryInfo = getLatestSharedLibraVersionLPr(parsedPackage);
                     if (libraryInfo != null) {
                         signatureCheckPs = mSettings.getPackageLPr(libraryInfo.getPackageName());
                     }
@@ -16344,23 +16103,23 @@
                 // bail early here before tripping over redefined permissions.
                 final KeySetManagerService ksms = mSettings.mKeySetManagerService;
                 if (ksms.shouldCheckUpgradeKeySetLocked(signatureCheckPs, scanFlags)) {
-                    if (!ksms.checkUpgradeKeySetLocked(signatureCheckPs, pkg)) {
+                    if (!ksms.checkUpgradeKeySetLocked(signatureCheckPs, parsedPackage)) {
                         throw new PrepareFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package "
-                                + pkg.packageName + " upgrade keys do not match the "
+                                + parsedPackage.getPackageName() + " upgrade keys do not match the "
                                 + "previously installed version");
                     }
                 } else {
                     try {
-                        final boolean compareCompat = isCompatSignatureUpdateNeeded(pkg);
-                        final boolean compareRecover = isRecoverSignatureUpdateNeeded(pkg);
+                        final boolean compareCompat = isCompatSignatureUpdateNeeded(parsedPackage);
+                        final boolean compareRecover = isRecoverSignatureUpdateNeeded(
+                                parsedPackage);
                         // We don't care about disabledPkgSetting on install for now.
-                        final boolean compatMatch = verifySignatures(
-                                signatureCheckPs, null, pkg.mSigningDetails, compareCompat,
-                                compareRecover);
+                        final boolean compatMatch = verifySignatures(signatureCheckPs, null,
+                                parsedPackage.getSigningDetails(), compareCompat, compareRecover);
                         // The new KeySets will be re-added later in the scanning process.
                         if (compatMatch) {
                             synchronized (mLock) {
-                                ksms.removeAppKeySetDataLPw(pkg.packageName);
+                                ksms.removeAppKeySetDataLPw(parsedPackage.getPackageName());
                             }
                         }
                     } catch (PackageManagerException e) {
@@ -16368,27 +16127,25 @@
                     }
                 }
 
-                if (ps.pkg != null && ps.pkg.applicationInfo != null) {
-                    systemApp = (ps.pkg.applicationInfo.flags &
-                            ApplicationInfo.FLAG_SYSTEM) != 0;
+                if (ps.pkg != null) {
+                    systemApp = (ps.pkg.getFlags() & ApplicationInfo.FLAG_SYSTEM) != 0;
                 }
                 res.origUsers = ps.queryInstalledUsers(mUserManager.getUserIds(), true);
             }
 
 
-            int N = pkg.permissions.size();
+            int N = ArrayUtils.size(parsedPackage.getPermissions());
             for (int i = N - 1; i >= 0; i--) {
-                final PackageParser.Permission perm = pkg.permissions.get(i);
-                final BasePermission bp =
-                        (BasePermission) mPermissionManager.getPermissionTEMP(perm.info.name);
+                final ParsedPermission perm = parsedPackage.getPermissions().get(i);
+                final BasePermission bp = mPermissionManager.getPermissionTEMP(perm.getName());
 
                 // Don't allow anyone but the system to define ephemeral permissions.
-                if ((perm.info.protectionLevel & PermissionInfo.PROTECTION_FLAG_INSTANT) != 0
+                if ((perm.protectionLevel & PermissionInfo.PROTECTION_FLAG_INSTANT) != 0
                         && !systemApp) {
-                    Slog.w(TAG, "Non-System package " + pkg.packageName
+                    Slog.w(TAG, "Non-System package " + parsedPackage.getPackageName()
                             + " attempting to delcare ephemeral permission "
-                            + perm.info.name + "; Removing ephemeral.");
-                    perm.info.protectionLevel &= ~PermissionInfo.PROTECTION_FLAG_INSTANT;
+                            + perm.getName() + "; Removing ephemeral.");
+                    perm.protectionLevel &= ~PermissionInfo.PROTECTION_FLAG_INSTANT;
                 }
 
                 // Check whether the newly-scanned package wants to define an already-defined perm
@@ -16400,26 +16157,27 @@
                     final String sourcePackageName = bp.getSourcePackageName();
                     final PackageSettingBase sourcePackageSetting = bp.getSourcePackageSetting();
                     final KeySetManagerService ksms = mSettings.mKeySetManagerService;
-                    if (sourcePackageName.equals(pkg.packageName)
+                    if (sourcePackageName.equals(parsedPackage.getPackageName())
                             && (ksms.shouldCheckUpgradeKeySetLocked(
                             sourcePackageSetting, scanFlags))) {
-                        sigsOk = ksms.checkUpgradeKeySetLocked(sourcePackageSetting, pkg);
+                        sigsOk = ksms.checkUpgradeKeySetLocked(sourcePackageSetting, parsedPackage);
                     } else {
 
                         // in the event of signing certificate rotation, we need to see if the
                         // package's certificate has rotated from the current one, or if it is an
                         // older certificate with which the current is ok with sharing permissions
                         if (sourcePackageSetting.signatures.mSigningDetails.checkCapability(
-                                pkg.mSigningDetails,
+                                parsedPackage.getSigningDetails(),
                                 PackageParser.SigningDetails.CertCapabilities.PERMISSION)) {
                             sigsOk = true;
-                        } else if (pkg.mSigningDetails.checkCapability(
+                        } else if (parsedPackage.getSigningDetails().checkCapability(
                                 sourcePackageSetting.signatures.mSigningDetails,
                                 PackageParser.SigningDetails.CertCapabilities.PERMISSION)) {
 
                             // the scanned package checks out, has signing certificate rotation
                             // history, and is newer; bring it over
-                            sourcePackageSetting.signatures.mSigningDetails = pkg.mSigningDetails;
+                            sourcePackageSetting.signatures.mSigningDetails =
+                                    parsedPackage.getSigningDetails();
                             sigsOk = true;
                         } else {
                             sigsOk = false;
@@ -16431,30 +16189,31 @@
                         // redefinitions.
                         if (!sourcePackageName.equals("android")) {
                             throw new PrepareFailure(INSTALL_FAILED_DUPLICATE_PERMISSION, "Package "
-                                    + pkg.packageName
+                                    + parsedPackage.getPackageName()
                                     + " attempting to redeclare permission "
-                                    + perm.info.name + " already owned by "
+                                    + perm.getName() + " already owned by "
                                     + sourcePackageName)
-                                    .conflictsWithExistingPermission(perm.info.name,
+                                    .conflictsWithExistingPermission(perm.getName(),
                                             sourcePackageName);
                         } else {
-                            Slog.w(TAG, "Package " + pkg.packageName
+                            Slog.w(TAG, "Package " + parsedPackage.getPackageName()
                                     + " attempting to redeclare system permission "
-                                    + perm.info.name + "; ignoring new declaration");
-                            pkg.permissions.remove(i);
+                                    + perm.getName() + "; ignoring new declaration");
+                            parsedPackage.removePermission(i);
                         }
-                    } else if (!PLATFORM_PACKAGE_NAME.equals(pkg.packageName)) {
+                    } else if (!PLATFORM_PACKAGE_NAME.equals(parsedPackage.getPackageName())) {
                         // Prevent apps to change protection level to dangerous from any other
                         // type as this would allow a privilege escalation where an app adds a
                         // normal/signature permission in other app's group and later redefines
                         // it as dangerous leading to the group auto-grant.
-                        if ((perm.info.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE)
+                        if ((perm.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE)
                                 == PermissionInfo.PROTECTION_DANGEROUS) {
                             if (bp != null && !bp.isRuntime()) {
-                                Slog.w(TAG, "Package " + pkg.packageName + " trying to change a "
-                                        + "non-runtime permission " + perm.info.name
+                                Slog.w(TAG, "Package " + parsedPackage.getPackageName()
+                                        + " trying to change a non-runtime permission "
+                                        + perm.getName()
                                         + " to runtime; keeping old protection level");
-                                perm.info.protectionLevel = bp.getProtectionLevel();
+                                perm.protectionLevel = bp.getProtectionLevel();
                             }
                         }
                     }
@@ -16488,8 +16247,8 @@
 
                 // We moved the entire application as-is, so bring over the
                 // previously derived ABI information.
-                pkg.applicationInfo.primaryCpuAbi = ps.primaryCpuAbiString;
-                pkg.applicationInfo.secondaryCpuAbi = ps.secondaryCpuAbiString;
+                parsedPackage.setPrimaryCpuAbi(ps.primaryCpuAbiString)
+                        .setSecondaryCpuAbi(ps.secondaryCpuAbiString);
             }
 
         } else {
@@ -16497,14 +16256,14 @@
             scanFlags |= SCAN_NO_DEX;
 
             try {
-                String abiOverride = (TextUtils.isEmpty(pkg.cpuAbiOverride) ?
-                        args.abiOverride : pkg.cpuAbiOverride);
-                final boolean extractNativeLibs = !pkg.isLibrary();
+                String abiOverride = (TextUtils.isEmpty(parsedPackage.getCpuAbiOverride())
+                        ? args.abiOverride : parsedPackage.getCpuAbiOverride());
+                final boolean extractNativeLibs = !parsedPackage.isLibrary();
                 final Pair<PackageAbiHelper.Abis, PackageAbiHelper.NativeLibraryPaths>
                         derivedAbi = mInjector.getAbiHelper().derivePackageAbi(
-                                pkg, abiOverride, extractNativeLibs);
-                derivedAbi.first.applyTo(pkg);
-                derivedAbi.second.applyTo(pkg);
+                                parsedPackage, abiOverride, extractNativeLibs);
+                derivedAbi.first.applyTo(parsedPackage);
+                derivedAbi.second.applyTo(parsedPackage);
             } catch (PackageManagerException pme) {
                 Slog.e(TAG, "Error deriving application ABI", pme);
                 throw new PrepareFailure(INSTALL_FAILED_INTERNAL_ERROR,
@@ -16512,19 +16271,19 @@
             }
         }
 
-        if (!args.doRename(res.returnCode, pkg)) {
+        if (!args.doRename(res.returnCode, parsedPackage)) {
             throw new PrepareFailure(INSTALL_FAILED_INSUFFICIENT_STORAGE, "Failed rename");
         }
 
         try {
-            setUpFsVerityIfPossible(pkg);
+            setUpFsVerityIfPossible(parsedPackage);
         } catch (InstallerException | IOException | DigestException | NoSuchAlgorithmException e) {
             throw new PrepareFailure(INSTALL_FAILED_INTERNAL_ERROR,
                     "Failed to set up verity: " + e);
         }
 
         if (!instantApp) {
-            startIntentFilterVerifications(args.user.getIdentifier(), replace, pkg);
+            startIntentFilterVerifications(args.user.getIdentifier(), replace, parsedPackage);
         } else {
             if (DEBUG_DOMAIN_VERIFICATION) {
                 Slog.d(TAG, "Not verifying instant app install for app links: " + pkgName);
@@ -16534,7 +16293,7 @@
                 freezePackageForInstall(pkgName, installFlags, "installPackageLI");
         boolean shouldCloseFreezerBeforeReturn = true;
         try {
-            final PackageParser.Package existingPackage;
+            final AndroidPackage existingPackage;
             String renamedPackage = null;
             boolean sysPkg = false;
             int targetScanFlags = scanFlags;
@@ -16548,9 +16307,10 @@
                     // and cannot be updated as an update would get a new package name,
                     // unless this is the exact same version code which is useful for
                     // development.
-                    PackageParser.Package existingPkg = mPackages.get(pkg.packageName);
+                    AndroidPackage existingPkg = mPackages.get(parsedPackage.getPackageName());
                     if (existingPkg != null
-                            && existingPkg.getLongVersionCode() != pkg.getLongVersionCode()) {
+                            && existingPkg.getLongVersionCode()
+                            != parsedPackage.getLongVersionCode()) {
                         throw new PrepareFailure(INSTALL_FAILED_DUPLICATE_PACKAGE,
                                 "Packages declaring "
                                         + "static-shared libs cannot be updated");
@@ -16559,8 +16319,8 @@
 
                 final boolean isInstantApp = (scanFlags & SCAN_AS_INSTANT_APP) != 0;
 
-                final PackageParser.Package oldPackage;
-                final String pkgName11 = pkg.packageName;
+                final AndroidPackage oldPackage;
+                final String pkgName11 = parsedPackage.getPackageName();
                 final int[] allUsers;
                 final int[] installedUsers;
 
@@ -16568,8 +16328,9 @@
                     oldPackage = mPackages.get(pkgName11);
                     existingPackage = oldPackage;
                     if (DEBUG_INSTALL) {
+                        // TODO(b/135203078): PackageImpl.toString()
                         Slog.d(TAG,
-                                "replacePackageLI: new=" + pkg + ", old=" + oldPackage);
+                                "replacePackageLI: new=" + parsedPackage + ", old=" + oldPackage);
                     }
 
                     ps = mSettings.mPackages.get(pkgName11);
@@ -16578,17 +16339,18 @@
                     // verify signatures are valid
                     final KeySetManagerService ksms = mSettings.mKeySetManagerService;
                     if (ksms.shouldCheckUpgradeKeySetLocked(ps, scanFlags)) {
-                        if (!ksms.checkUpgradeKeySetLocked(ps, pkg)) {
+                        if (!ksms.checkUpgradeKeySetLocked(ps, parsedPackage)) {
                             throw new PrepareFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
                                     "New package not signed by keys specified by upgrade-keysets: "
                                             + pkgName11);
                         }
                     } else {
                         // default to original signature matching
-                        if (!pkg.mSigningDetails.checkCapability(oldPackage.mSigningDetails,
+                        if (!parsedPackage.getSigningDetails().checkCapability(
+                                oldPackage.getSigningDetails(),
                                 SigningDetails.CertCapabilities.INSTALLED_DATA)
-                                && !oldPackage.mSigningDetails.checkCapability(
-                                pkg.mSigningDetails,
+                                && !oldPackage.getSigningDetails().checkCapability(
+                                parsedPackage.getSigningDetails(),
                                 SigningDetails.CertCapabilities.ROLLBACK)) {
                             throw new PrepareFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
                                     "New package has a different signature: " + pkgName11);
@@ -16596,13 +16358,13 @@
                     }
 
                     // don't allow a system upgrade unless the upgrade hash matches
-                    if (oldPackage.restrictUpdateHash != null && oldPackage.isSystem()) {
+                    if (oldPackage.getRestrictUpdateHash() != null && oldPackage.isSystem()) {
                         final byte[] digestBytes;
                         try {
                             final MessageDigest digest = MessageDigest.getInstance("SHA-512");
-                            updateDigest(digest, new File(pkg.baseCodePath));
-                            if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) {
-                                for (String path : pkg.splitCodePaths) {
+                            updateDigest(digest, new File(parsedPackage.getBaseCodePath()));
+                            if (!ArrayUtils.isEmpty(parsedPackage.getSplitCodePaths())) {
+                                for (String path : parsedPackage.getSplitCodePaths()) {
                                     updateDigest(digest, new File(path));
                                 }
                             }
@@ -16611,21 +16373,25 @@
                             throw new PrepareFailure(INSTALL_FAILED_INVALID_APK,
                                     "Could not compute hash: " + pkgName11);
                         }
-                        if (!Arrays.equals(oldPackage.restrictUpdateHash, digestBytes)) {
+                        if (!Arrays.equals(oldPackage.getRestrictUpdateHash(), digestBytes)) {
                             throw new PrepareFailure(INSTALL_FAILED_INVALID_APK,
                                     "New package fails restrict-update check: " + pkgName11);
                         }
                         // retain upgrade restriction
-                        pkg.restrictUpdateHash = oldPackage.restrictUpdateHash;
+                        parsedPackage.setRestrictUpdateHash(oldPackage.getRestrictUpdateHash());
                     }
 
                     // Check for shared user id changes
-                    String invalidPackageName =
-                            getParentOrChildPackageChangedSharedUser(oldPackage, pkg);
+                    String invalidPackageName = null;
+                    if (!Objects.equals(oldPackage.getSharedUserId(),
+                            parsedPackage.getSharedUserId())) {
+                        invalidPackageName = parsedPackage.getPackageName();
+                    }
+
                     if (invalidPackageName != null) {
                         throw new PrepareFailure(INSTALL_FAILED_SHARED_USER_INCOMPATIBLE,
                                 "Package " + invalidPackageName + " tried to change user "
-                                        + oldPackage.mSharedUserId);
+                                        + oldPackage.getSharedUserId());
                     }
 
                     // In case of rollback, remember per-user/profile install state
@@ -16735,41 +16501,30 @@
                             | (odm ? SCAN_AS_ODM : 0);
 
                     if (DEBUG_INSTALL) {
-                        Slog.d(TAG, "replaceSystemPackageLI: new=" + pkg
+                        Slog.d(TAG, "replaceSystemPackageLI: new=" + parsedPackage
                                 + ", old=" + oldPackage);
                     }
                     res.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
-                    pkg.setApplicationInfoFlags(ApplicationInfo.FLAG_UPDATED_SYSTEM_APP,
-                            ApplicationInfo.FLAG_UPDATED_SYSTEM_APP);
+                    parsedPackage.setUpdatedSystemApp(true);
                     targetParseFlags = systemParseFlags;
                     targetScanFlags = systemScanFlags;
                 } else { // non system replace
                     replace = true;
                     if (DEBUG_INSTALL) {
                         Slog.d(TAG,
-                                "replaceNonSystemPackageLI: new=" + pkg + ", old="
+                                "replaceNonSystemPackageLI: new=" + parsedPackage + ", old="
                                         + oldPackage);
                     }
-
-                    String pkgName1 = oldPackage.packageName;
-                    boolean deletedPkg = true;
-                    boolean addedPkg = false;
-                    boolean updatedSettings = false;
-
-                    final long origUpdateTime = (pkg.mExtras != null)
-                            ? ((PackageSetting) pkg.mExtras).lastUpdateTime : 0;
-
                 }
             } else { // new package install
                 ps = null;
-                childPackages = null;
                 disabledPs = null;
                 replace = false;
                 existingPackage = null;
                 // Remember this for later, in case we need to rollback this install
-                String pkgName1 = pkg.packageName;
+                String pkgName1 = parsedPackage.getPackageName();
 
-                if (DEBUG_INSTALL) Slog.d(TAG, "installNewPackageLI: " + pkg);
+                if (DEBUG_INSTALL) Slog.d(TAG, "installNewPackageLI: " + parsedPackage);
 
                 // TODO(patb): MOVE TO RECONCILE
                 synchronized (mLock) {
@@ -16812,7 +16567,7 @@
      * <p>When the feature flag is set to legacy mode, only APK is supported (with some experimental
      * kernel patches). In normal mode, all file format can be supported.
      */
-    private void setUpFsVerityIfPossible(PackageParser.Package pkg) throws InstallerException,
+    private void setUpFsVerityIfPossible(AndroidPackage pkg) throws InstallerException,
             PrepareFailure, IOException, DigestException, NoSuchAlgorithmException {
         final boolean standardMode = PackageManagerServiceUtils.isApkVerityEnabled();
         final boolean legacyMode = PackageManagerServiceUtils.isLegacyApkVerityEnabled();
@@ -16824,11 +16579,11 @@
         ArrayMap<String, String> fsverityCandidates = new ArrayMap<>();
         if (legacyMode) {
             synchronized (mLock) {
-                final PackageSetting ps = mSettings.mPackages.get(pkg.packageName);
+                final PackageSetting ps = mSettings.mPackages.get(pkg.getPackageName());
                 if (ps != null && ps.isPrivileged()) {
-                    fsverityCandidates.put(pkg.baseCodePath, null);
-                    if (pkg.splitCodePaths != null) {
-                        for (String splitPath : pkg.splitCodePaths) {
+                    fsverityCandidates.put(pkg.getBaseCodePath(), null);
+                    if (pkg.getSplitCodePaths() != null) {
+                        for (String splitPath : pkg.getSplitCodePaths()) {
                             fsverityCandidates.put(splitPath, null);
                         }
                     }
@@ -16837,16 +16592,17 @@
         } else {
             // NB: These files will become only accessible if the signing key is loaded in kernel's
             // .fs-verity keyring.
-            fsverityCandidates.put(pkg.baseCodePath,
-                    VerityUtils.getFsveritySignatureFilePath(pkg.baseCodePath));
+            fsverityCandidates.put(pkg.getBaseCodePath(),
+                    VerityUtils.getFsveritySignatureFilePath(pkg.getBaseCodePath()));
 
-            final String dmPath = DexMetadataHelper.buildDexMetadataPathForApk(pkg.baseCodePath);
+            final String dmPath = DexMetadataHelper.buildDexMetadataPathForApk(
+                    pkg.getBaseCodePath());
             if (new File(dmPath).exists()) {
                 fsverityCandidates.put(dmPath, VerityUtils.getFsveritySignatureFilePath(dmPath));
             }
 
-            if (pkg.splitCodePaths != null) {
-                for (String path : pkg.splitCodePaths) {
+            if (pkg.getSplitCodePaths() != null) {
+                for (String path : pkg.getSplitCodePaths()) {
                     fsverityCandidates.put(path, VerityUtils.getFsveritySignatureFilePath(path));
 
                     final String splitDmPath = DexMetadataHelper.buildDexMetadataPathForApk(path);
@@ -16900,8 +16656,7 @@
         }
     }
 
-    private void startIntentFilterVerifications(int userId, boolean replacing,
-            PackageParser.Package pkg) {
+    private void startIntentFilterVerifications(int userId, boolean replacing, AndroidPackage pkg) {
         if (mIntentFilterVerifierComponent == null) {
             Slog.w(TAG, "No IntentFilter verification will not be done as "
                     + "there is no IntentFilterVerifier available!");
@@ -16914,29 +16669,29 @@
                 (userId == UserHandle.USER_ALL) ? UserHandle.USER_SYSTEM : userId);
 
         Message msg = mHandler.obtainMessage(START_INTENT_FILTER_VERIFICATIONS);
-        msg.obj = new IFVerificationParams(pkg, replacing, userId, verifierUid);
+        msg.obj = new IFVerificationParams(
+                pkg.getPackageName(),
+                hasDomainURLs(pkg),
+                pkg.getActivities(),
+                replacing,
+                userId,
+                verifierUid
+        );
         mHandler.sendMessage(msg);
-
-        final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
-        for (int i = 0; i < childCount; i++) {
-            PackageParser.Package childPkg = pkg.childPackages.get(i);
-            msg = mHandler.obtainMessage(START_INTENT_FILTER_VERIFICATIONS);
-            msg.obj = new IFVerificationParams(childPkg, replacing, userId, verifierUid);
-            mHandler.sendMessage(msg);
-        }
     }
 
     private void verifyIntentFiltersIfNeeded(int userId, int verifierUid, boolean replacing,
-            PackageParser.Package pkg) {
-        int size = pkg.activities.size();
+            String packageName,
+            boolean hasDomainUrls,
+            List<ParsedActivity> activities) {
+        int size = activities.size();
         if (size == 0) {
             if (DEBUG_DOMAIN_VERIFICATION) Slog.d(TAG,
                     "No activity, so no need to verify any IntentFilter!");
             return;
         }
 
-        final boolean hasDomainURLs = hasDomainURLs(pkg);
-        if (!hasDomainURLs) {
+        if (!hasDomainUrls) {
             if (DEBUG_DOMAIN_VERIFICATION) Slog.d(TAG,
                     "No domain URLs, so no need to verify any IntentFilter!");
             return;
@@ -16947,7 +16702,6 @@
                 + " Activities needs verification ...");
 
         int count = 0;
-        final String packageName = pkg.packageName;
 
         synchronized (mLock) {
             // If this is a new install and we see that we've already run verification for this
@@ -16966,8 +16720,8 @@
 
             // If any filters need to be verified, then all need to be.
             boolean needToVerify = false;
-            for (PackageParser.Activity a : pkg.activities) {
-                for (ActivityIntentInfo filter : a.intents) {
+            for (ParsedActivity a : activities) {
+                for (ParsedActivityIntentInfo filter : a.intents) {
                     if (filter.needsVerification() && needsNetworkVerificationLPr(filter)) {
                         if (DEBUG_DOMAIN_VERIFICATION) {
                             Slog.d(TAG,
@@ -16981,8 +16735,8 @@
 
             if (needToVerify) {
                 final int verificationId = mIntentFilterVerificationToken++;
-                for (PackageParser.Activity a : pkg.activities) {
-                    for (ActivityIntentInfo filter : a.intents) {
+                for (ParsedActivity a : activities) {
+                    for (ParsedActivityIntentInfo filter : a.intents) {
                         if (filter.handlesWebUris(true) && needsNetworkVerificationLPr(filter)) {
                             if (DEBUG_DOMAIN_VERIFICATION) Slog.d(TAG,
                                     "Verification needed for IntentFilter:" + filter.toString());
@@ -17008,9 +16762,8 @@
     }
 
     @GuardedBy("mLock")
-    private boolean needsNetworkVerificationLPr(ActivityIntentInfo filter) {
-        final ComponentName cn  = filter.activity.getComponentName();
-        final String packageName = cn.getPackageName();
+    private boolean needsNetworkVerificationLPr(ParsedActivityIntentInfo filter) {
+        final String packageName = filter.getPackageName();
 
         IntentFilterVerificationInfo ivi = mSettings.getIntentFilterVerificationLPr(
                 packageName);
@@ -17030,45 +16783,45 @@
         }
     }
 
-    private static boolean isExternal(PackageParser.Package pkg) {
-        return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0;
+    private static boolean isExternal(AndroidPackage pkg) {
+        return (pkg.getFlags() & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0;
     }
 
     private static boolean isExternal(PackageSetting ps) {
         return (ps.pkgFlags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0;
     }
 
-    static boolean isSystemApp(PackageParser.Package pkg) {
-        return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
+    static boolean isSystemApp(AndroidPackage pkg) {
+        return (pkg.getFlags() & ApplicationInfo.FLAG_SYSTEM) != 0;
     }
 
-    private static boolean isPrivilegedApp(PackageParser.Package pkg) {
-        return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
+    private static boolean isPrivilegedApp(AndroidPackage pkg) {
+        return (pkg.getPrivateFlags() & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
     }
 
-    private static boolean isOemApp(PackageParser.Package pkg) {
-        return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_OEM) != 0;
+    private static boolean isOemApp(AndroidPackage pkg) {
+        return (pkg.getPrivateFlags() & ApplicationInfo.PRIVATE_FLAG_OEM) != 0;
     }
 
-    private static boolean isVendorApp(PackageParser.Package pkg) {
-        return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0;
+    private static boolean isVendorApp(AndroidPackage pkg) {
+        return (pkg.getPrivateFlags() & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0;
     }
 
-    private static boolean isProductApp(PackageParser.Package pkg) {
-        return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT) != 0;
+    private static boolean isProductApp(AndroidPackage pkg) {
+        return (pkg.getPrivateFlags() & ApplicationInfo.PRIVATE_FLAG_PRODUCT) != 0;
     }
 
-    private static boolean isSystemExtApp(PackageParser.Package pkg) {
-        return (pkg.applicationInfo.privateFlags
+    private static boolean isSystemExtApp(AndroidPackage pkg) {
+        return (pkg.getPrivateFlags()
                 & ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT) != 0;
     }
 
-    private static boolean isOdmApp(PackageParser.Package pkg) {
-        return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_ODM) != 0;
+    private static boolean isOdmApp(AndroidPackage pkg) {
+        return (pkg.getPrivateFlags() & ApplicationInfo.PRIVATE_FLAG_ODM) != 0;
     }
 
-    private static boolean hasDomainURLs(PackageParser.Package pkg) {
-        return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS) != 0;
+    private static boolean hasDomainURLs(AndroidPackage pkg) {
+        return (pkg.getPrivateFlags() & ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS) != 0;
     }
 
     private static boolean isSystemApp(PackageSetting ps) {
@@ -17079,12 +16832,12 @@
         return (ps.pkgFlags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0;
     }
 
-    private VersionInfo getSettingsVersionForPackage(PackageParser.Package pkg) {
+    private VersionInfo getSettingsVersionForPackage(AndroidPackage pkg) {
         if (isExternal(pkg)) {
-            if (TextUtils.isEmpty(pkg.volumeUuid)) {
+            if (TextUtils.isEmpty(pkg.getVolumeUuid())) {
                 return mSettings.getExternalVersion();
             } else {
-                return mSettings.findOrCreateVersion(pkg.volumeUuid);
+                return mSettings.findOrCreateVersion(pkg.getVolumeUuid());
             }
         } else {
             return mSettings.getInternalVersion();
@@ -17092,6 +16845,7 @@
     }
 
     private void deleteTempPackageFiles() {
+        // TODO: Is this used?
         final FilenameFilter filter =
                 (dir, name) -> name.startsWith("vmdl") && name.endsWith(".tmp");
     }
@@ -17225,11 +16979,11 @@
         });
     }
 
-    private String resolveExternalPackageNameLPr(PackageParser.Package pkg) {
-        if (pkg.staticSharedLibName != null) {
-            return pkg.manifestPackageName;
+    private String resolveExternalPackageNameLPr(AndroidPackage pkg) {
+        if (pkg.getStaticSharedLibName() != null) {
+            return pkg.getManifestPackageName();
         }
-        return pkg.packageName;
+        return pkg.getPackageName();
     }
 
     @GuardedBy("mLock")
@@ -17436,7 +17190,7 @@
 
         final PackageSetting uninstalledPs;
         final PackageSetting disabledSystemPs;
-        final PackageParser.Package pkg;
+        final AndroidPackage pkg;
 
         // for the uninstall-updates case and restricted profiles, remember the per-
         // user handle installed state
@@ -17468,9 +17222,9 @@
 
             allUsers = mUserManager.getUserIds();
 
-            if (pkg != null && pkg.staticSharedLibName != null) {
-                SharedLibraryInfo libraryInfo = getSharedLibraryInfoLPr(pkg.staticSharedLibName,
-                        pkg.staticSharedLibVersion);
+            if (pkg != null && pkg.getStaticSharedLibName() != null) {
+                SharedLibraryInfo libraryInfo = getSharedLibraryInfoLPr(
+                        pkg.getStaticSharedLibName(), pkg.getStaticSharedLibVersion());
                 if (libraryInfo != null) {
                     for (int currUserId : allUsers) {
                         if (removeUser != UserHandle.USER_ALL && removeUser != currUserId) {
@@ -17479,7 +17233,7 @@
                         List<VersionedPackage> libClientPackages = getPackagesUsingSharedLibraryLPr(
                                 libraryInfo, MATCH_KNOWN_PACKAGES, currUserId);
                         if (!ArrayUtils.isEmpty(libClientPackages)) {
-                            Slog.w(TAG, "Not removing package " + pkg.manifestPackageName
+                            Slog.w(TAG, "Not removing package " + pkg.getManifestPackageName()
                                     + " hosting lib " + libraryInfo.getName() + " version "
                                     + libraryInfo.getLongVersion() + " used by " + libClientPackages
                                     + " for user " + currUserId);
@@ -17534,13 +17288,13 @@
             if (info.args != null) {
                 info.args.doPostDeleteLI(true);
             }
-            final PackageParser.Package stubPkg =
+            final AndroidPackage stubPkg =
                     (disabledSystemPs == null) ? null : disabledSystemPs.pkg;
-            if (stubPkg != null && stubPkg.isStub) {
+            if (stubPkg != null && stubPkg.isStub()) {
                 synchronized (mLock) {
                     // restore the enabled state of the stub; the state is overwritten when
                     // the stub is uninstalled
-                    final PackageSetting stubPs = mSettings.mPackages.get(stubPkg.packageName);
+                    final PackageSetting stubPs = mSettings.mPackages.get(stubPkg.getPackageName());
                     if (stubPs != null) {
                         stubPs.setEnabled(origEnabledState, userId, "android");
                     }
@@ -17549,7 +17303,7 @@
                         || origEnabledState == COMPONENT_ENABLED_STATE_ENABLED) {
                     if (DEBUG_COMPRESSION) {
                         Slog.i(TAG, "Enabling system stub after removal; pkg: "
-                                + stubPkg.packageName);
+                                + stubPkg.getPackageName());
                     }
                     enableCompressedPackage(stubPkg);
                 }
@@ -17577,7 +17331,6 @@
         boolean isStaticSharedLib;
         // Clean up resources deleted packages.
         InstallArgs args = null;
-        ArrayMap<String, PackageRemovedInfo> removedChildPackages;
         ArrayMap<String, PackageInstalledInfo> appearedChildPackages;
 
         PackageRemovedInfo(PackageSender packageSender) {
@@ -17586,24 +17339,11 @@
 
         void sendPackageRemovedBroadcasts(boolean killApp) {
             sendPackageRemovedBroadcastInternal(killApp);
-            final int childCount = removedChildPackages != null ? removedChildPackages.size() : 0;
-            for (int i = 0; i < childCount; i++) {
-                PackageRemovedInfo childInfo = removedChildPackages.valueAt(i);
-                childInfo.sendPackageRemovedBroadcastInternal(killApp);
-            }
         }
 
         void sendSystemPackageUpdatedBroadcasts() {
             if (isRemovedPackageSystemUpdate) {
                 sendSystemPackageUpdatedBroadcastsInternal();
-                final int childCount = (removedChildPackages != null)
-                        ? removedChildPackages.size() : 0;
-                for (int i = 0; i < childCount; i++) {
-                    PackageRemovedInfo childInfo = removedChildPackages.valueAt(i);
-                    if (childInfo.isRemovedPackageSystemUpdate) {
-                        childInfo.sendSystemPackageUpdatedBroadcastsInternal();
-                    }
-                }
             }
         }
 
@@ -17715,12 +17455,12 @@
         String packageName = deletedPs.name;
         if (DEBUG_REMOVE) Slog.d(TAG, "removePackageDataLI: " + deletedPs);
         // Retrieve object to delete permissions for shared user later on
-        final PackageParser.Package deletedPkg = deletedPs.pkg;
+        final AndroidPackage deletedPkg = deletedPs.pkg;
         if (outInfo != null) {
             outInfo.removedPackage = packageName;
             outInfo.installerPackageName = deletedPs.installSource.installerPackageName;
             outInfo.isStaticSharedLib = deletedPkg != null
-                    && deletedPkg.staticSharedLibName != null;
+                    && deletedPkg.getStaticSharedLibName() != null;
             outInfo.populateUsers(deletedPs == null ? null
                     : deletedPs.queryInstalledUsers(mUserManager.getUserIds(), true), deletedPs);
         }
@@ -17728,14 +17468,14 @@
         removePackageLI(deletedPs.name, (flags & PackageManager.DELETE_CHATTY) != 0);
 
         if ((flags & PackageManager.DELETE_KEEP_DATA) == 0) {
-            final PackageParser.Package resolvedPkg;
+            final AndroidPackage resolvedPkg;
             if (deletedPkg != null) {
                 resolvedPkg = deletedPkg;
             } else {
                 // We don't have a parsed package when it lives on an ejected
                 // adopted storage device, so fake something together
-                resolvedPkg = new PackageParser.Package(deletedPs.name);
-                resolvedPkg.setVolumeUuid(deletedPs.volumeUuid);
+                resolvedPkg = PackageImpl.buildFakeForDeletion(deletedPs.name,
+                        deletedPs.volumeUuid);
             }
             destroyAppDataLIF(resolvedPkg, UserHandle.USER_ALL,
                     FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL);
@@ -17849,13 +17589,13 @@
             throws SystemDeleteException {
         final boolean applyUserRestrictions =
                 (allUserHandles != null) && outInfo != null && (outInfo.origUsers != null);
-        final PackageParser.Package deletedPkg = deletedPs.pkg;
+        final AndroidPackage deletedPkg = deletedPs.pkg;
         // Confirm if the system package has been updated
         // An updated system app can be deleted. This will also have to restore
         // the system pkg from system partition
         // reader
         final PackageSetting disabledPs = action.disabledPs;
-        if (DEBUG_REMOVE) Slog.d(TAG, "deleteSystemPackageLI: newPs=" + deletedPkg.packageName
+        if (DEBUG_REMOVE) Slog.d(TAG, "deleteSystemPackageLI: newPs=" + deletedPkg.getPackageName()
                 + " disabledPs=" + disabledPs);
         Slog.d(TAG, "Deleting system pkg from data partition");
 
@@ -17872,21 +17612,6 @@
         if (outInfo != null) {
             // Delete the updated package
             outInfo.isRemovedPackageSystemUpdate = true;
-            if (outInfo.removedChildPackages != null) {
-                final int childCount = (deletedPs.childPackageNames != null)
-                        ? deletedPs.childPackageNames.size() : 0;
-                for (int i = 0; i < childCount; i++) {
-                    String childPackageName = deletedPs.childPackageNames.get(i);
-                    if (disabledPs.childPackageNames != null && disabledPs.childPackageNames
-                            .contains(childPackageName)) {
-                        PackageRemovedInfo childInfo = outInfo.removedChildPackages.get(
-                                childPackageName);
-                        if (childInfo != null) {
-                            childInfo.isRemovedPackageSystemUpdate = true;
-                        }
-                    }
-                }
-            }
         }
 
         if (disabledPs.versionCode < deletedPs.versionCode) {
@@ -17898,7 +17623,7 @@
         }
 
         deleteInstalledPackageLIF(deletedPs, true, flags, allUserHandles,
-                outInfo, writeSettings, disabledPs.pkg);
+                outInfo, writeSettings);
 
         // writer
         synchronized (mLock) {
@@ -17919,16 +17644,16 @@
                     outInfo == null ? null : outInfo.origUsers, deletedPs.getPermissionsState(),
                     writeSettings);
         } catch (PackageManagerException e) {
-            Slog.w(TAG, "Failed to restore system package:" + deletedPkg.packageName + ": "
+            Slog.w(TAG, "Failed to restore system package:" + deletedPkg.getPackageName() + ": "
                     + e.getMessage());
             // TODO(patb): can we avoid this; throw would come from scan...
             throw new SystemDeleteException(e);
         } finally {
-            if (disabledPs.pkg.isStub) {
+            if (disabledPs.pkg.isStub()) {
                 // We've re-installed the stub; make sure it's disabled here. If package was
                 // originally enabled, we'll install the compressed version of the application
                 // and re-enable it afterward.
-                final PackageSetting stubPs = mSettings.mPackages.get(deletedPkg.packageName);
+                final PackageSetting stubPs = mSettings.mPackages.get(deletedPkg.getPackageName());
                 if (stubPs != null) {
                     stubPs.setEnabled(
                             COMPONENT_ENABLED_STATE_DISABLED, UserHandle.USER_SYSTEM, "android");
@@ -17940,7 +17665,7 @@
     /**
      * Installs a package that's already on the system partition.
      */
-    private PackageParser.Package installPackageFromSystemLIF(@NonNull String codePathString,
+    private AndroidPackage installPackageFromSystemLIF(@NonNull String codePathString,
             @Nullable int[] allUserHandles, @Nullable int[] origUserHandles,
             @Nullable PermissionsState origPermissionState, boolean writeSettings)
                     throws PackageManagerException {
@@ -17961,7 +17686,7 @@
         }
 
         final File codePath = new File(codePathString);
-        final PackageParser.Package pkg =
+        final AndroidPackage pkg =
                 scanPackageTracedLI(codePath, parseFlags, scanFlags, 0 /*currentTime*/, null);
 
         try {
@@ -17975,7 +17700,7 @@
 
         // writer
         synchronized (mLock) {
-            PackageSetting ps = mSettings.mPackages.get(pkg.packageName);
+            PackageSetting ps = mSettings.mPackages.get(pkg.getPackageName());
 
             // Propagate the permissions state as we do not want to drop on the floor
             // runtime permissions. The update permissions method below will take
@@ -17983,7 +17708,7 @@
             if (origPermissionState != null) {
                 ps.getPermissionsState().copyFrom(origPermissionState);
             }
-            mPermissionManager.updatePermissions(pkg.packageName, pkg);
+            mPermissionManager.updatePermissions(pkg.getPackageName(), pkg);
 
             final boolean applyUserRestrictions
                     = (allUserHandles != null) && (origUserHandles != null);
@@ -18021,58 +17746,22 @@
 
     private void deleteInstalledPackageLIF(PackageSetting ps,
             boolean deleteCodeAndResources, int flags, int[] allUserHandles,
-            PackageRemovedInfo outInfo, boolean writeSettings,
-            PackageParser.Package replacingPackage) {
+            PackageRemovedInfo outInfo, boolean writeSettings) {
         synchronized (mLock) {
             if (outInfo != null) {
                 outInfo.uid = ps.appId;
             }
-
-            if (outInfo != null && outInfo.removedChildPackages != null) {
-                final int childCount = (ps.childPackageNames != null)
-                        ? ps.childPackageNames.size() : 0;
-                for (int i = 0; i < childCount; i++) {
-                    String childPackageName = ps.childPackageNames.get(i);
-                    PackageSetting childPs = mSettings.mPackages.get(childPackageName);
-                    PackageRemovedInfo childInfo = outInfo.removedChildPackages.get(
-                            childPackageName);
-                    if (childInfo != null) {
-                        childInfo.uid = childPs.appId;
-                    }
-                }
-            }
         }
 
         // Delete package data from internal structures and also remove data if flag is set
         removePackageDataLIF(ps, allUserHandles, outInfo, flags, writeSettings);
 
-        // Delete the child packages data
-        final int childCount = (ps.childPackageNames != null) ? ps.childPackageNames.size() : 0;
-        for (int i = 0; i < childCount; i++) {
-            PackageSetting childPs;
-            synchronized (mLock) {
-                childPs = mSettings.getPackageLPr(ps.childPackageNames.get(i));
-            }
-            if (childPs != null) {
-                PackageRemovedInfo childOutInfo = (outInfo != null
-                        && outInfo.removedChildPackages != null)
-                        ? outInfo.removedChildPackages.get(childPs.name) : null;
-                final int deleteFlags = (flags & DELETE_KEEP_DATA) != 0
-                        && (replacingPackage != null
-                        && !replacingPackage.hasChildPackage(childPs.name))
-                        ? flags & ~DELETE_KEEP_DATA : flags;
-                removePackageDataLIF(childPs, allUserHandles, childOutInfo,
-                        deleteFlags, writeSettings);
-            }
-        }
-
         // Delete application code and resources only for parent packages
-        if (ps.parentPackageName == null) {
-            if (deleteCodeAndResources && (outInfo != null)) {
-                outInfo.args = createInstallArgsForExisting(
-                        ps.codePathString, ps.resourcePathString, getAppDexInstructionSets(ps));
-                if (DEBUG_SD_INSTALL) Slog.i(TAG, "args=" + outInfo.args);
-            }
+        if (deleteCodeAndResources && (outInfo != null)) {
+            outInfo.args = createInstallArgsForExisting(
+                    ps.codePathString, ps.resourcePathString, getAppDexInstructionSets(
+                            ps.primaryCpuAbiString, ps.secondaryCpuAbiString));
+            if (DEBUG_SD_INSTALL) Slog.i(TAG, "args=" + outInfo.args);
         }
     }
 
@@ -18085,10 +17774,10 @@
             // Cannot block uninstall of static shared libs as they are
             // considered a part of the using app (emulating static linking).
             // Also static libs are installed always on internal storage.
-            PackageParser.Package pkg = mPackages.get(packageName);
-            if (pkg != null && pkg.staticSharedLibName != null) {
+            AndroidPackage pkg = mPackages.get(packageName);
+            if (pkg != null && pkg.getStaticSharedLibName() != null) {
                 Slog.w(TAG, "Cannot block uninstall of package: " + packageName
-                        + " providing static shared library: " + pkg.staticSharedLibName);
+                        + " providing static shared library: " + pkg.getStaticSharedLibName());
                 return false;
             }
             mSettings.setBlockUninstallLPw(userId, packageName, blockUninstall);
@@ -18152,40 +17841,22 @@
     @GuardedBy("mLock")
     private static DeletePackageAction mayDeletePackageLocked(
             PackageRemovedInfo outInfo, PackageSetting ps, @Nullable PackageSetting disabledPs,
-            @Nullable PackageSetting[] children, int flags, UserHandle user) {
+            int flags, UserHandle user) {
         if (ps == null) {
             return null;
         }
         if (isSystemApp(ps)) {
-            if (ps.parentPackageName != null) {
-                Slog.w(TAG, "Attempt to delete child system package " + ps.pkg.packageName);
-                return null;
-            }
-
             final boolean deleteSystem = (flags & PackageManager.DELETE_SYSTEM_APP) != 0;
             final boolean deleteAllUsers =
                     user == null || user.getIdentifier() == UserHandle.USER_ALL;
             if ((!deleteSystem || deleteAllUsers) && disabledPs == null) {
-                Slog.w(TAG, "Attempt to delete unknown system package " + ps.pkg.packageName);
+                Slog.w(TAG, "Attempt to delete unknown system package " + ps.pkg.getPackageName());
                 return null;
             }
             // Confirmed if the system package has been updated
             // An updated system app can be deleted. This will also have to restore
             // the system pkg from system partition reader
         }
-        final int parentReferenceCount =
-                (ps.childPackageNames != null) ? ps.childPackageNames.size() : 0;
-        final int childCount = children != null ? children.length : 0;
-        if (childCount != parentReferenceCount) {
-            return null;
-        }
-        if (childCount != 0 && outInfo != null && outInfo.removedChildPackages != null) {
-            for (PackageSetting child : children) {
-                if (child == null || !ps.childPackageNames.contains(child.name)) {
-                    return null;
-                }
-            }
-        }
         return new DeletePackageAction(ps, disabledPs, outInfo, flags, user);
     }
 
@@ -18195,13 +17866,12 @@
     private boolean deletePackageLIF(@NonNull String packageName, UserHandle user,
             boolean deleteCodeAndResources, int[] allUserHandles, int flags,
             PackageRemovedInfo outInfo, boolean writeSettings,
-            PackageParser.Package replacingPackage) {
+            ParsedPackage replacingPackage) {
         final DeletePackageAction action;
         synchronized (mLock) {
             final PackageSetting ps = mSettings.mPackages.get(packageName);
             final PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(ps);
-            PackageSetting[] children = mSettings.getChildSettingsLPr(ps);
-            action = mayDeletePackageLocked(outInfo, ps, disabledPs, children, flags, user);
+            action = mayDeletePackageLocked(outInfo, ps, disabledPs, flags, user);
         }
         if (DEBUG_REMOVE) Slog.d(TAG, "deletePackageLI: " + packageName + " user " + user);
         if (null == action) {
@@ -18232,30 +17902,13 @@
     private void executeDeletePackageLIF(DeletePackageAction action,
             String packageName, boolean deleteCodeAndResources,
             int[] allUserHandles, boolean writeSettings,
-            PackageParser.Package replacingPackage) throws SystemDeleteException {
+            ParsedPackage replacingPackage) throws SystemDeleteException {
         final PackageSetting ps = action.deletingPs;
         final PackageRemovedInfo outInfo = action.outInfo;
         final UserHandle user = action.user;
         final int flags = action.flags;
         final boolean systemApp = isSystemApp(ps);
 
-        if (ps.parentPackageName != null
-                && (!systemApp || (flags & PackageManager.DELETE_SYSTEM_APP) != 0)) {
-            if (DEBUG_REMOVE) {
-                Slog.d(TAG, "Uninstalled child package:" + packageName + " for user:"
-                        + ((user == null) ? UserHandle.USER_ALL : user));
-            }
-            final int removedUserId = (user != null) ? user.getIdentifier()
-                    : UserHandle.USER_ALL;
-
-            clearPackageStateForUserLIF(ps, removedUserId, outInfo, flags);
-            synchronized (mLock) {
-                markPackageUninstalledForUserLPw(ps, user);
-                scheduleWritePackageRestrictionsLocked(user);
-            }
-            return;
-        }
-
         final int userId = user == null ? UserHandle.USER_ALL : user.getIdentifier();
         if (ps.getPermissionsState().hasPermission(Manifest.permission.SUSPEND_APPS, userId)) {
             unsuspendForSuspendingPackage(packageName, userId);
@@ -18334,53 +17987,12 @@
         } else {
             if (DEBUG_REMOVE) Slog.d(TAG, "Removing non-system package: " + ps.name);
             deleteInstalledPackageLIF(ps, deleteCodeAndResources, flags, allUserHandles,
-                    outInfo, writeSettings, replacingPackage);
+                    outInfo, writeSettings);
         }
 
         // Take a note whether we deleted the package for all users
         if (outInfo != null) {
             outInfo.removedForAllUsers = mPackages.get(ps.name) == null;
-            if (outInfo.removedChildPackages != null) {
-                synchronized (mLock) {
-                    final int childCount = outInfo.removedChildPackages.size();
-                    for (int i = 0; i < childCount; i++) {
-                        PackageRemovedInfo childInfo = outInfo.removedChildPackages.valueAt(i);
-                        if (childInfo != null) {
-                            childInfo.removedForAllUsers = mPackages.get(
-                                    childInfo.removedPackage) == null;
-                        }
-                    }
-                }
-            }
-            // If we uninstalled an update to a system app there may be some
-            // child packages that appeared as they are declared in the system
-            // app but were not declared in the update.
-            if (systemApp) {
-                synchronized (mLock) {
-                    PackageSetting updatedPs = mSettings.getPackageLPr(ps.name);
-                    final int childCount = (updatedPs.childPackageNames != null)
-                            ? updatedPs.childPackageNames.size() : 0;
-                    for (int i = 0; i < childCount; i++) {
-                        String childPackageName = updatedPs.childPackageNames.get(i);
-                        if (outInfo.removedChildPackages == null
-                                || outInfo.removedChildPackages.indexOfKey(childPackageName) < 0) {
-                            PackageSetting childPs = mSettings.getPackageLPr(childPackageName);
-                            if (childPs == null) {
-                                continue;
-                            }
-                            PackageInstalledInfo installRes = new PackageInstalledInfo();
-                            installRes.name = childPackageName;
-                            installRes.newUsers = childPs.queryInstalledUsers(allUserHandles, true);
-                            installRes.pkg = mPackages.get(childPackageName);
-                            installRes.uid = childPs.pkg.applicationInfo.uid;
-                            if (outInfo.appearedChildPackages == null) {
-                                outInfo.appearedChildPackages = new ArrayMap<>();
-                            }
-                            outInfo.appearedChildPackages.put(childPackageName, installRes);
-                        }
-                    }
-                }
-            }
         }
     }
 
@@ -18414,7 +18026,7 @@
 
     private void clearPackageStateForUserLIF(PackageSetting ps, int userId,
             PackageRemovedInfo outInfo, int flags) {
-        final PackageParser.Package pkg;
+        final AndroidPackage pkg;
         synchronized (mLock) {
             pkg = mPackages.get(ps.name);
         }
@@ -18467,7 +18079,7 @@
     public void clearApplicationProfileData(String packageName) {
         enforceSystemOrRoot("Only the system can clear all profile data");
 
-        final PackageParser.Package pkg;
+        final AndroidPackage pkg;
         synchronized (mLock) {
             pkg = mPackages.get(packageName);
         }
@@ -18545,7 +18157,7 @@
         }
 
         // Try finding details about the requested package
-        PackageParser.Package pkg;
+        AndroidPackage pkg;
         synchronized (mLock) {
             pkg = mPackages.get(packageName);
             if (pkg == null) {
@@ -18564,7 +18176,7 @@
         clearAppDataLIF(pkg, userId,
                 FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL);
 
-        final int appId = UserHandle.getAppId(pkg.applicationInfo.uid);
+        final int appId = UserHandle.getAppId(pkg.getUid());
         removeKeystoreDataIfNeeded(mInjector.getUserManagerInternal(), userId, appId);
 
         UserManagerInternal umInternal = mInjector.getUserManagerInternal();
@@ -18641,14 +18253,14 @@
         final int hasAccessInstantApps = mContext.checkCallingOrSelfPermission(
                 android.Manifest.permission.ACCESS_INSTANT_APPS);
 
-        final PackageParser.Package pkg;
+        final AndroidPackage pkg;
         synchronized (mLock) {
             pkg = mPackages.get(packageName);
         }
 
         // Queue up an async operation since the package deletion may take a little while.
         mHandler.post(() -> {
-            final PackageSetting ps = pkg == null ? null : (PackageSetting) pkg.mExtras;
+            final PackageSetting ps = pkg == null ? null : getPackageSetting(pkg.getPackageName());
             boolean doClearData = true;
             if (ps != null) {
                 final boolean targetIsInstantApp =
@@ -18728,7 +18340,7 @@
             while (it.hasNext()) {
                 final PackageSetting ps = it.next();
                 if (ps.pkg != null) {
-                    int v = ps.pkg.applicationInfo.targetSdkVersion;
+                    int v = ps.pkg.getTargetSdkVersion();
                     if (v < vers) vers = v;
                 }
             }
@@ -18736,7 +18348,7 @@
         } else if (obj instanceof PackageSetting) {
             final PackageSetting ps = (PackageSetting) obj;
             if (ps.pkg != null) {
-                return ps.pkg.applicationInfo.targetSdkVersion;
+                return ps.pkg.getTargetSdkVersion();
             }
         }
         return Build.VERSION_CODES.CUR_DEVELOPMENT;
@@ -18744,9 +18356,9 @@
 
     @GuardedBy("mLock")
     private int getPackageTargetSdkVersionLockedLPr(String packageName) {
-        final PackageParser.Package p = mPackages.get(packageName);
+        final AndroidPackage p = mPackages.get(packageName);
         if (p != null) {
-            return p.applicationInfo.targetSdkVersion;
+            return p.getTargetSdkVersion();
         }
         return Build.VERSION_CODES.CUR_DEVELOPMENT;
     }
@@ -18915,7 +18527,7 @@
         }
         // writer
         synchronized (mLock) {
-            PackageParser.Package pkg = mPackages.get(packageName);
+            AndroidPackage pkg = mPackages.get(packageName);
             if (pkg == null || !isCallerSameApp(packageName, callingUid)) {
                 if (mContext.checkCallingOrSelfPermission(
                         android.Manifest.permission.SET_PREFERRED_APPLICATIONS)
@@ -18989,8 +18601,8 @@
     private void clearIntentFilterVerificationsLPw(int userId) {
         final int packageCount = mPackages.size();
         for (int i = 0; i < packageCount; i++) {
-            PackageParser.Package pkg = mPackages.valueAt(i);
-            clearIntentFilterVerificationsLPw(pkg.packageName, userId);
+            AndroidPackage pkg = mPackages.valueAt(i);
+            clearIntentFilterVerificationsLPw(pkg.getPackageName(), userId);
         }
     }
 
@@ -19938,8 +19550,8 @@
             // If we're enabling a system stub, there's a little more work to do.
             // Prior to enabling the package, we need to decompress the APK(s) to the
             // data partition and then replace the version on the system partition.
-            final PackageParser.Package deletedPkg = pkgSetting.pkg;
-            final boolean isSystemStub = deletedPkg.isStub
+            final AndroidPackage deletedPkg = pkgSetting.pkg;
+            final boolean isSystemStub = deletedPkg.isStub()
                     && deletedPkg.isSystem();
             if (isSystemStub
                     && (newState == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
@@ -19960,10 +19572,10 @@
             synchronized (mLock) {
                 // We're dealing with a component level state change
                 // First, verify that this is a valid class name.
-                PackageParser.Package pkg = pkgSetting.pkg;
+                AndroidPackage pkg = pkgSetting.pkg;
                 if (pkg == null || !pkg.hasComponentClassName(className)) {
                     if (pkg != null &&
-                            pkg.applicationInfo.targetSdkVersion >=
+                            pkg.getTargetSdkVersion() >=
                                     Build.VERSION_CODES.JELLY_BEAN) {
                         throw new IllegalArgumentException("Component class " + className
                                 + " does not exist in " + packageName);
@@ -21024,7 +20636,7 @@
 
             if (!checkin && dumpState.isDumping(DumpState.DUMP_SERVICE_PERMISSIONS)
                     && packageName == null) {
-                mComponentResolver.dumpServicePermissions(pw, dumpState, packageName);
+                mComponentResolver.dumpServicePermissions(pw, dumpState);
             }
 
             if (!checkin && dumpState.isDumping(DumpState.DUMP_DEXOPT)) {
@@ -21167,9 +20779,9 @@
         ipw.println();
         ipw.println("Dexopt state:");
         ipw.increaseIndent();
-        Collection<PackageParser.Package> packages;
+        Collection<AndroidPackage> packages;
         if (packageName != null) {
-            PackageParser.Package targetPackage = mPackages.get(packageName);
+            AndroidPackage targetPackage = mPackages.get(packageName);
             if (targetPackage != null) {
                 packages = Collections.singletonList(targetPackage);
             } else {
@@ -21180,11 +20792,11 @@
             packages = mPackages.values();
         }
 
-        for (PackageParser.Package pkg : packages) {
-            ipw.println("[" + pkg.packageName + "]");
+        for (AndroidPackage pkg : packages) {
+            ipw.println("[" + pkg.getPackageName() + "]");
             ipw.increaseIndent();
             mPackageDexOptimizer.dumpDexoptState(ipw, pkg,
-                    mDexManager.getPackageUseInfoOrDefault(pkg.packageName));
+                    mDexManager.getPackageUseInfoOrDefault(pkg.getPackageName()));
             ipw.decreaseIndent();
         }
     }
@@ -21196,9 +20808,9 @@
         ipw.println();
         ipw.println("Compiler stats:");
         ipw.increaseIndent();
-        Collection<PackageParser.Package> packages;
+        Collection<AndroidPackage> packages;
         if (packageName != null) {
-            PackageParser.Package targetPackage = mPackages.get(packageName);
+            AndroidPackage targetPackage = mPackages.get(packageName);
             if (targetPackage != null) {
                 packages = Collections.singletonList(targetPackage);
             } else {
@@ -21209,11 +20821,11 @@
             packages = mPackages.values();
         }
 
-        for (PackageParser.Package pkg : packages) {
-            ipw.println("[" + pkg.packageName + "]");
+        for (AndroidPackage pkg : packages) {
+            ipw.println("[" + pkg.getPackageName() + "]");
             ipw.increaseIndent();
 
-            CompilerStats.PackageStats stats = getCompilerPackageStats(pkg.packageName);
+            CompilerStats.PackageStats stats = getCompilerPackageStats(pkg.getPackageName());
             if (stats == null) {
                 ipw.println("(No recorded stats)");
             } else {
@@ -21284,14 +20896,14 @@
     }
 
     private void sendResourcesChangedBroadcast(boolean mediaStatus, boolean replacing,
-            ArrayList<ApplicationInfo> infos, IIntentReceiver finishedReceiver) {
-        final int size = infos.size();
+            ArrayList<AndroidPackage> packages, IIntentReceiver finishedReceiver) {
+        final int size = packages.size();
         final String[] packageNames = new String[size];
         final int[] packageUids = new int[size];
         for (int i = 0; i < size; i++) {
-            final ApplicationInfo info = infos.get(i);
-            packageNames[i] = info.packageName;
-            packageUids[i] = info.uid;
+            final AndroidPackage pkg = packages.get(i);
+            packageNames[i] = pkg.getAppInfoPackageName();
+            packageUids[i] = pkg.getUid();
         }
         sendResourcesChangedBroadcast(mediaStatus, replacing, packageNames, packageUids,
                 finishedReceiver);
@@ -21334,7 +20946,7 @@
         }
 
         final ArrayList<PackageFreezer> freezers = new ArrayList<>();
-        final ArrayList<ApplicationInfo> loaded = new ArrayList<>();
+        final ArrayList<AndroidPackage> loaded = new ArrayList<>();
         final int parseFlags = mDefParseFlags | PackageParser.PARSE_EXTERNAL_STORAGE;
 
         final VersionInfo ver;
@@ -21347,10 +20959,10 @@
         for (PackageSetting ps : packages) {
             freezers.add(freezePackage(ps.name, "loadPrivatePackagesInner"));
             synchronized (mInstallLock) {
-                final PackageParser.Package pkg;
+                final AndroidPackage pkg;
                 try {
                     pkg = scanPackageTracedLI(ps.codePath, parseFlags, SCAN_INITIAL, 0, null);
-                    loaded.add(pkg.applicationInfo);
+                    loaded.add(pkg);
 
                 } catch (PackageManagerException e) {
                     Slog.w(TAG, "Failed to scan " + ps.codePath + ": " + e.getMessage());
@@ -21422,14 +21034,14 @@
             return;
         }
 
-        final ArrayList<ApplicationInfo> unloaded = new ArrayList<>();
+        final ArrayList<AndroidPackage> unloaded = new ArrayList<>();
         synchronized (mInstallLock) {
         synchronized (mLock) {
             final List<PackageSetting> packages = mSettings.getVolumePackagesLPr(volumeUuid);
             for (PackageSetting ps : packages) {
                 if (ps.pkg == null) continue;
 
-                final ApplicationInfo info = ps.pkg.applicationInfo;
+                final AndroidPackage pkg = ps.pkg;
                 final int deleteFlags = PackageManager.DELETE_KEEP_DATA;
                 final PackageRemovedInfo outInfo = new PackageRemovedInfo(this);
 
@@ -21437,7 +21049,7 @@
                         "unloadPrivatePackagesInner")) {
                     if (deletePackageLIF(ps.name, null, false, null, deleteFlags, outInfo,
                             false, null)) {
-                        unloaded.add(info);
+                        unloaded.add(pkg);
                     } else {
                         Slog.w(TAG, "Failed to unload " + ps.codePath);
                     }
@@ -21652,7 +21264,7 @@
                 continue;
             }
             // Skip non-core apps if requested
-            if (onlyCoreApps && !ps.pkg.coreApp) {
+            if (onlyCoreApps && !ps.pkg.isCoreApp()) {
                 result.add(packageName);
                 continue;
             }
@@ -21679,10 +21291,10 @@
      * <p>
      * <em>Note: To avoid a deadlock, do not call this method with {@code mLock} lock held</em>
      */
-    private void prepareAppDataAfterInstallLIF(PackageParser.Package pkg) {
+    private void prepareAppDataAfterInstallLIF(AndroidPackage pkg) {
         final PackageSetting ps;
         synchronized (mLock) {
-            ps = mSettings.mPackages.get(pkg.packageName);
+            ps = mSettings.mPackages.get(pkg.getPackageName());
             mSettings.writeKernelMappingLPr(ps);
         }
 
@@ -21712,19 +21324,15 @@
      * will try recovering system apps by wiping data; third-party app data is
      * left intact.
      */
-    private void prepareAppDataLIF(PackageParser.Package pkg, int userId, int flags) {
+    private void prepareAppDataLIF(AndroidPackage pkg, int userId, int flags) {
         if (pkg == null) {
             Slog.wtf(TAG, "Package was null!", new Throwable());
             return;
         }
         prepareAppDataLeafLIF(pkg, userId, flags);
-        final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
-        for (int i = 0; i < childCount; i++) {
-            prepareAppDataLeafLIF(pkg.childPackages.get(i), userId, flags);
-        }
     }
 
-    private void prepareAppDataAndMigrateLIF(PackageParser.Package pkg, int userId, int flags,
+    private void prepareAppDataAndMigrateLIF(AndroidPackage pkg, int userId, int flags,
             boolean maybeMigrateAppData) {
         prepareAppDataLIF(pkg, userId, flags);
 
@@ -21735,43 +21343,37 @@
         }
     }
 
-    private void prepareAppDataLeafLIF(PackageParser.Package pkg, int userId, int flags) {
+    private void prepareAppDataLeafLIF(AndroidPackage pkg, int userId, int flags) {
         if (DEBUG_APP_DATA) {
-            Slog.v(TAG, "prepareAppData for " + pkg.packageName + " u" + userId + " 0x"
+            Slog.v(TAG, "prepareAppData for " + pkg.getPackageName() + " u" + userId + " 0x"
                     + Integer.toHexString(flags));
         }
 
         final PackageSetting ps;
         synchronized (mLock) {
-            ps = mSettings.mPackages.get(pkg.packageName);
+            ps = mSettings.mPackages.get(pkg.getPackageName());
         }
-        final String volumeUuid = pkg.volumeUuid;
-        final String packageName = pkg.packageName;
+        final String volumeUuid = pkg.getVolumeUuid();
+        final String packageName = pkg.getPackageName();
 
-        ApplicationInfo app = (ps == null)
-                ? pkg.applicationInfo
-                : PackageParser.generateApplicationInfo(pkg, 0, ps.readUserState(userId), userId);
-        if (app == null) {
-            app = pkg.applicationInfo;
-        }
+        final int appId = UserHandle.getAppId(pkg.getUid());
 
-        final int appId = UserHandle.getAppId(app.uid);
+        Preconditions.checkNotNull(pkg.getSeInfo());
 
-        Preconditions.checkNotNull(app.seInfo);
-
-        final String seInfo = app.seInfo + (app.seInfoUser != null ? app.seInfoUser : "");
+        final String seInfo =
+                pkg.getSeInfo() + (pkg.getSeInfoUser() != null ? pkg.getSeInfoUser() : "");
         long ceDataInode = -1;
         try {
             ceDataInode = mInstaller.createAppData(volumeUuid, packageName, userId, flags,
-                    appId, seInfo, app.targetSdkVersion);
+                    appId, seInfo, pkg.getTargetSdkVersion());
         } catch (InstallerException e) {
-            if (app.isSystemApp()) {
+            if (pkg.isSystemApp()) {
                 logCriticalInfo(Log.ERROR, "Failed to create app data for " + packageName
                         + ", but trying to recover: " + e);
                 destroyAppDataLeafLIF(pkg, userId, flags);
                 try {
                     ceDataInode = mInstaller.createAppData(volumeUuid, packageName, userId, flags,
-                            appId, seInfo, app.targetSdkVersion);
+                            appId, seInfo, pkg.getTargetSdkVersion());
                     logCriticalInfo(Log.DEBUG, "Recovery succeeded!");
                 } catch (InstallerException e2) {
                     logCriticalInfo(Log.DEBUG, "Recovery failed!");
@@ -21813,29 +21415,24 @@
         prepareAppDataContentsLeafLIF(pkg, userId, flags);
     }
 
-    private void prepareAppDataContentsLIF(PackageParser.Package pkg, int userId, int flags) {
+    private void prepareAppDataContentsLIF(AndroidPackage pkg, int userId, int flags) {
         if (pkg == null) {
             Slog.wtf(TAG, "Package was null!", new Throwable());
             return;
         }
         prepareAppDataContentsLeafLIF(pkg, userId, flags);
-        final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
-        for (int i = 0; i < childCount; i++) {
-            prepareAppDataContentsLeafLIF(pkg.childPackages.get(i), userId, flags);
-        }
     }
 
-    private void prepareAppDataContentsLeafLIF(PackageParser.Package pkg, int userId, int flags) {
-        final String volumeUuid = pkg.volumeUuid;
-        final String packageName = pkg.packageName;
-        final ApplicationInfo app = pkg.applicationInfo;
+    private void prepareAppDataContentsLeafLIF(AndroidPackage pkg, int userId, int flags) {
+        final String volumeUuid = pkg.getVolumeUuid();
+        final String packageName = pkg.getPackageName();
 
         if ((flags & StorageManager.FLAG_STORAGE_CE) != 0) {
             // Create a native library symlink only if we have native libraries
             // and if the native libraries are 32 bit libraries. We do not provide
             // this symlink for 64 bit libraries.
-            if (app.primaryCpuAbi != null && !VMRuntime.is64BitAbi(app.primaryCpuAbi)) {
-                final String nativeLibPath = app.nativeLibraryDir;
+            if (pkg.getPrimaryCpuAbi() != null && !VMRuntime.is64BitAbi(pkg.getPrimaryCpuAbi())) {
+                final String nativeLibPath = pkg.getNativeLibraryDir();
                 try {
                     mInstaller.linkNativeLibraryDirectory(volumeUuid, packageName,
                             nativeLibPath, userId);
@@ -21851,17 +21448,17 @@
      * CE/DE data to match the {@code defaultToDeviceProtectedStorage} flag
      * requested by the app.
      */
-    private boolean maybeMigrateAppDataLIF(PackageParser.Package pkg, int userId) {
+    private boolean maybeMigrateAppDataLIF(AndroidPackage pkg, int userId) {
         if (pkg.isSystem() && !StorageManager.isFileEncryptedNativeOrEmulated()
                 && PackageManager.APPLY_DEFAULT_TO_DEVICE_PROTECTED_STORAGE) {
-            final int storageTarget = pkg.applicationInfo.isDefaultToDeviceProtectedStorage()
+            final int storageTarget = pkg.isDefaultToDeviceProtectedStorage()
                     ? StorageManager.FLAG_STORAGE_DE : StorageManager.FLAG_STORAGE_CE;
             try {
-                mInstaller.migrateAppData(pkg.volumeUuid, pkg.packageName, userId,
+                mInstaller.migrateAppData(pkg.getVolumeUuid(), pkg.getPackageName(), userId,
                         storageTarget);
             } catch (InstallerException e) {
                 logCriticalInfo(Log.WARN,
-                        "Failed to migrate " + pkg.packageName + ": " + e.getMessage());
+                        "Failed to migrate " + pkg.getPackageName() + ": " + e.getMessage());
             }
             return true;
         } else {
@@ -21912,7 +21509,6 @@
      */
     private class PackageFreezer implements AutoCloseable {
         private final String mPackageName;
-        private final PackageFreezer[] mChildren;
 
         private final boolean mWeFroze;
 
@@ -21927,7 +21523,6 @@
          */
         public PackageFreezer() {
             mPackageName = null;
-            mChildren = null;
             mWeFroze = false;
             mCloseGuard.open("close");
         }
@@ -21941,18 +21536,6 @@
                 if (ps != null) {
                     killApplication(ps.name, ps.appId, userId, killReason);
                 }
-
-                final PackageParser.Package p = mPackages.get(packageName);
-                if (p != null && p.childPackages != null) {
-                    final int N = p.childPackages.size();
-                    mChildren = new PackageFreezer[N];
-                    for (int i = 0; i < N; i++) {
-                        mChildren[i] = new PackageFreezer(p.childPackages.get(i).packageName,
-                                userId, killReason);
-                    }
-                } else {
-                    mChildren = null;
-                }
             }
             mCloseGuard.open("close");
         }
@@ -21975,12 +21558,6 @@
                     if (mWeFroze) {
                         mFrozenPackages.remove(mPackageName);
                     }
-
-                    if (mChildren != null) {
-                        for (PackageFreezer freezer : mChildren) {
-                            freezer.close();
-                        }
-                    }
                 }
             }
         }
@@ -22035,14 +21612,14 @@
 
         // reader
         synchronized (mLock) {
-            final PackageParser.Package pkg = mPackages.get(packageName);
+            final AndroidPackage pkg = mPackages.get(packageName);
             final PackageSetting ps = mSettings.mPackages.get(packageName);
             if (pkg == null
                     || ps == null
                     || shouldFilterApplicationLocked(ps, callingUid, user.getIdentifier())) {
                 throw new PackageManagerException(MOVE_FAILED_DOESNT_EXIST, "Missing package");
             }
-            if (pkg.applicationInfo.isSystemApp()) {
+            if (pkg.isSystemApp()) {
                 throw new PackageManagerException(MOVE_FAILED_SYSTEM_PACKAGE,
                         "Cannot move system application");
             }
@@ -22057,7 +21634,7 @@
 
             currentVolumeUuid = ps.volumeUuid;
 
-            final File probe = new File(pkg.codePath);
+            final File probe = new File(pkg.getCodePath());
             final File probeOat = new File(probe, "oat");
             if (!probe.isDirectory() || !probeOat.isDirectory()) {
                 throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR,
@@ -22068,7 +21645,7 @@
                 throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR,
                         "Package already moved to " + volumeUuid);
             }
-            if (pkg.applicationInfo.isInternal() && isPackageDeviceAdminOnAnyUser(packageName)) {
+            if (pkg.isInternal() && isPackageDeviceAdminOnAnyUser(packageName)) {
                 throw new PackageManagerException(MOVE_FAILED_DEVICE_ADMIN,
                         "Device admin cannot be moved");
             }
@@ -22082,10 +21659,10 @@
             codeFile = new File(pkg.codePath);
             installSource = ps.installSource;
             packageAbiOverride = ps.cpuAbiOverrideString;
-            appId = UserHandle.getAppId(pkg.applicationInfo.uid);
-            seinfo = pkg.applicationInfo.seInfo;
-            label = String.valueOf(pm.getApplicationLabel(pkg.applicationInfo));
-            targetSdkVersion = pkg.applicationInfo.targetSdkVersion;
+            appId = UserHandle.getAppId(pkg.getUid());
+            seinfo = pkg.getSeInfo();
+            label = String.valueOf(pm.getApplicationLabel(pkg.toAppInfo()));
+            targetSdkVersion = pkg.getTargetSdkVersion();
             freezer = freezePackage(packageName, "movePackageInternal");
             installedUserIds = ps.queryInstalledUsers(mUserManager.getUserIds(), true);
         }
@@ -22246,7 +21823,7 @@
      * @param packageName The package that was moved.
      */
     private void logAppMovedStorage(String packageName, boolean isPreviousLocationExternal) {
-        final PackageParser.Package pkg;
+        final AndroidPackage pkg;
         synchronized (mLock) {
             pkg = mPackages.get(packageName);
         }
@@ -22254,8 +21831,8 @@
             return;
         }
 
-        final StorageManager storage = mInjector.getStorageManager();
-        VolumeInfo volume = storage.findVolumeByUuid(pkg.applicationInfo.storageUuid.toString());
+        final StorageManager storage = mInjector.getStorageManager();;
+        VolumeInfo volume = storage.findVolumeByUuid(pkg.getStorageUuid().toString());
         int packageExternalStorageType = getPackageExternalStorageType(volume, isExternal(pkg));
 
         if (!isPreviousLocationExternal && isExternal(pkg)) {
@@ -22499,13 +22076,13 @@
         if (packageName == null || alias == null) {
             return null;
         }
-        synchronized (mLock) {
-            final PackageParser.Package pkg = mPackages.get(packageName);
+        synchronized(mLock) {
+            final AndroidPackage pkg = mPackages.get(packageName);
             if (pkg == null) {
                 Slog.w(TAG, "KeySet requested for unknown package: " + packageName);
                 throw new IllegalArgumentException("Unknown package: " + packageName);
             }
-            final PackageSetting ps = (PackageSetting) pkg.mExtras;
+            final PackageSetting ps = getPackageSetting(pkg.getPackageName());
             if (shouldFilterApplicationLocked(
                     ps, Binder.getCallingUid(), UserHandle.getCallingUserId())) {
                 Slog.w(TAG, "KeySet requested for filtered package: " + packageName);
@@ -22524,19 +22101,19 @@
         synchronized (mLock) {
             final int callingUid = Binder.getCallingUid();
             final int callingUserId = UserHandle.getUserId(callingUid);
-            final PackageParser.Package pkg = mPackages.get(packageName);
+            final AndroidPackage pkg = mPackages.get(packageName);
             if (pkg == null) {
                 Slog.w(TAG, "KeySet requested for unknown package: " + packageName);
                 throw new IllegalArgumentException("Unknown package: " + packageName);
             }
-            final PackageSetting ps = (PackageSetting) pkg.mExtras;
+            final PackageSetting ps = getPackageSetting(pkg.getPackageName());
             if (shouldFilterApplicationLocked(ps, callingUid, callingUserId)) {
                 // filter and pretend the package doesn't exist
                 Slog.w(TAG, "KeySet requested for filtered package: " + packageName
                         + ", uid:" + callingUid);
                 throw new IllegalArgumentException("Unknown package: " + packageName);
             }
-            if (pkg.applicationInfo.uid != callingUid
+            if (pkg.getUid() != callingUid
                     && Process.SYSTEM_UID != callingUid) {
                 throw new SecurityException("May not access signing KeySet of other apps.");
             }
@@ -22554,11 +22131,11 @@
         if (packageName == null || ks == null) {
             return false;
         }
-        synchronized (mLock) {
-            final PackageParser.Package pkg = mPackages.get(packageName);
+        synchronized(mLock) {
+            final AndroidPackage pkg = mPackages.get(packageName);
             if (pkg == null
-                    || shouldFilterApplicationLocked((PackageSetting) pkg.mExtras, callingUid,
-                            UserHandle.getUserId(callingUid))) {
+                    || shouldFilterApplicationLocked(getPackageSetting(pkg.getPackageName()),
+                    callingUid, UserHandle.getUserId(callingUid))) {
                 Slog.w(TAG, "KeySet requested for unknown package: " + packageName);
                 throw new IllegalArgumentException("Unknown package: " + packageName);
             }
@@ -22581,10 +22158,10 @@
             return false;
         }
         synchronized (mLock) {
-            final PackageParser.Package pkg = mPackages.get(packageName);
+            final AndroidPackage pkg = mPackages.get(packageName);
             if (pkg == null
-                    || shouldFilterApplicationLocked((PackageSetting) pkg.mExtras, callingUid,
-                            UserHandle.getUserId(callingUid))) {
+                    || shouldFilterApplicationLocked(getPackageSetting(pkg.getPackageName()),
+                    callingUid, UserHandle.getUserId(callingUid))) {
                 Slog.w(TAG, "KeySet requested for unknown package: " + packageName);
                 throw new IllegalArgumentException("Unknown package: " + packageName);
             }
@@ -22616,29 +22193,29 @@
      * Check and throw if the given before/after packages would be considered a
      * downgrade.
      */
-    private static void checkDowngrade(PackageParser.Package before, PackageInfoLite after)
+    private static void checkDowngrade(AndroidPackage before, PackageInfoLite after)
             throws PackageManagerException {
         if (after.getLongVersionCode() < before.getLongVersionCode()) {
             throw new PackageManagerException(INSTALL_FAILED_VERSION_DOWNGRADE,
                     "Update version code " + after.versionCode + " is older than current "
                     + before.getLongVersionCode());
         } else if (after.getLongVersionCode() == before.getLongVersionCode()) {
-            if (after.baseRevisionCode < before.baseRevisionCode) {
+            if (after.baseRevisionCode < before.getBaseRevisionCode()) {
                 throw new PackageManagerException(INSTALL_FAILED_VERSION_DOWNGRADE,
                         "Update base revision code " + after.baseRevisionCode
-                        + " is older than current " + before.baseRevisionCode);
+                        + " is older than current " + before.getBaseRevisionCode());
             }
 
             if (!ArrayUtils.isEmpty(after.splitNames)) {
                 for (int i = 0; i < after.splitNames.length; i++) {
                     final String splitName = after.splitNames[i];
-                    final int j = ArrayUtils.indexOf(before.splitNames, splitName);
+                    final int j = ArrayUtils.indexOf(before.getSplitNames(), splitName);
                     if (j != -1) {
-                        if (after.splitRevisionCodes[i] < before.splitRevisionCodes[j]) {
+                        if (after.splitRevisionCodes[i] < before.getSplitRevisionCodes()[j]) {
                             throw new PackageManagerException(INSTALL_FAILED_VERSION_DOWNGRADE,
                                     "Update split " + splitName + " revision code "
                                     + after.splitRevisionCodes[i] + " is older than current "
-                                    + before.splitRevisionCodes[j]);
+                                    + before.getSplitRevisionCodes()[j]);
                         }
                     }
                 }
@@ -22828,13 +22405,13 @@
             if (packageSetting == null) {
                 return false;
             }
-            PackageParser.Package pkg = packageSetting.pkg;
+            AndroidPackage pkg = packageSetting.pkg;
             if (pkg == null) {
                 // May happen if package in on a removable sd card
                 return false;
             }
-            return pkg.mSigningDetails.hasAncestorOrSelf(mPlatformPackage.mSigningDetails)
-                    || mPlatformPackage.mSigningDetails.checkCapability(pkg.mSigningDetails,
+            return pkg.getSigningDetails().hasAncestorOrSelf(mPlatformPackage.getSigningDetails())
+                    || mPlatformPackage.getSigningDetails().checkCapability(pkg.getSigningDetails(),
                     PackageParser.SigningDetails.CertCapabilities.PERMISSION);
         }
 
@@ -22870,11 +22447,11 @@
 
         private SigningDetails getSigningDetails(@NonNull String packageName) {
             synchronized (mLock) {
-                PackageParser.Package p = mPackages.get(packageName);
+                AndroidPackage p = mPackages.get(packageName);
                 if (p == null) {
                     return null;
                 }
-                return p.mSigningDetails;
+                return p.getSigningDetails();
             }
         }
 
@@ -22905,28 +22482,25 @@
         }
 
         @Override
-        public boolean filterAppAccess(PackageParser.Package pkg, int callingUid, int userId) {
+        public boolean filterAppAccess(AndroidPackage pkg, int callingUid, int userId) {
             synchronized (mLock) {
-                return PackageManagerService.this.shouldFilterApplicationLocked(
-                        (PackageSetting) pkg.mExtras, callingUid, userId);
+                PackageSetting ps = getPackageSetting(pkg.getPackageName());
+                return PackageManagerService.this.shouldFilterApplicationLocked(ps, callingUid,
+                        userId);
             }
         }
 
         @Override
         public boolean filterAppAccess(String packageName, int callingUid, int userId) {
             synchronized (mLock) {
-                final PackageParser.Package pkg = mPackages.get(packageName);
-                if (pkg == null) {
-                    return false;
-                }
-                return PackageManagerService.this
-                        .shouldFilterApplicationLocked(
-                                (PackageSetting) pkg.mExtras, callingUid, userId);
+                PackageSetting ps = getPackageSetting(packageName);
+                return PackageManagerService.this.shouldFilterApplicationLocked(ps, callingUid,
+                        userId);
             }
         }
 
         @Override
-        public PackageParser.Package getPackage(String packageName) {
+        public AndroidPackage getPackage(String packageName) {
             synchronized (mLock) {
                 packageName = resolveInternalPackageNameLPr(
                         packageName, PackageManager.VERSION_CODE_HIGHEST);
@@ -22935,10 +22509,10 @@
         }
 
         @Override
-        public PackageParser.Package getPackage(int uid) {
+        public AndroidPackage getPackage(int uid) {
             synchronized (mLock) {
                 final String[] packageNames = getPackagesForUid(uid);
-                PackageParser.Package pkg = null;
+                AndroidPackage pkg = null;
                 final int numPackages = packageNames == null ? 0 : packageNames.length;
                 for (int i = 0; pkg == null && i < numPackages; i++) {
                     pkg = mPackages.get(packageNames[i]);
@@ -22947,6 +22521,12 @@
             }
         }
 
+        @Nullable
+        @Override
+        public PackageSetting getPackageSetting(String packageName) {
+            return PackageManagerService.this.getPackageSetting(packageName);
+        }
+
         @Override
         public PackageList getPackageList(PackageListObserver observer) {
             synchronized (mLock) {
@@ -22971,17 +22551,19 @@
         }
 
         @Override
-        public PackageParser.Package getDisabledSystemPackage(String packageName) {
+        public Object getDisabledSystemPackage(@NonNull String packageName) {
             synchronized (mLock) {
-                final PackageSetting ps = mSettings.getDisabledSystemPkgLPr(packageName);
-                return (ps != null) ? ps.pkg : null;
+                return mSettings.getDisabledSystemPkgLPr(packageName);
             }
         }
 
         @Override
-        public @Nullable String getDisabledSystemPackageName(@NonNull String packageName) {
-            PackageParser.Package pkg = getDisabledSystemPackage(packageName);
-            return pkg == null ? null : pkg.packageName;
+        public @Nullable
+        String getDisabledSystemPackageName(@NonNull String packageName) {
+            PackageSetting disabledPkgSetting = (PackageSetting) getDisabledSystemPackage(
+                    packageName);
+            AndroidPackage disabledPkg = disabledPkgSetting == null ? null : disabledPkgSetting.pkg;
+            return disabledPkg == null ? null : disabledPkg.getPackageName();
         }
 
         /**
@@ -23094,7 +22676,7 @@
         @Override
         public boolean isPermissionsReviewRequired(String packageName, int userId) {
             synchronized (mLock) {
-                final PackageParser.Package pkg = mPackages.get(packageName);
+                final AndroidPackage pkg = mPackages.get(packageName);
                 if (pkg == null) {
                     return false;
                 }
@@ -23280,9 +22862,10 @@
         }
 
         @Override
-        public boolean isEnabledAndMatches(ComponentInfo info, int flags, int userId) {
+        public boolean isEnabledAndMatches(ParsedComponent component, int flags, int userId) {
             synchronized (mLock) {
-                return mSettings.isEnabledAndMatchLPr(info, flags, userId);
+                AndroidPackage pkg = getPackage(component.getPackageName());
+                return mSettings.isEnabledAndMatchLPr(pkg, component, flags, userId);
             }
         }
 
@@ -23299,10 +22882,10 @@
         }
 
         @Override
-        public boolean setInstalled(PackageParser.Package pkg, @UserIdInt int userId,
+        public boolean setInstalled(AndroidPackage pkg, @UserIdInt int userId,
                 boolean installed) {
             synchronized (mLock) {
-                final PackageSetting ps = mSettings.mPackages.get(pkg.packageName);
+                final PackageSetting ps = mSettings.mPackages.get(pkg.getPackageName());
                 if (ps.getInstalled(userId) != installed) {
                     ps.setInstalled(installed, userId);
                     return true;
@@ -23332,8 +22915,8 @@
                     return;
                 }
 
-                final boolean instantApp = isInstantAppInternal(callingPackage.packageName, userId,
-                        callingUid);
+                final boolean instantApp = isInstantAppInternal(callingPackage.getPackageName(),
+                        userId, callingUid);
                 if (instantApp) {
                     mInstantAppRegistry.grantInstantAccessLPw(userId, intent,
                             UserHandle.getAppId(callingUid), targetAppId);
@@ -23370,9 +22953,9 @@
         @Override
         public boolean isPackagePersistent(String packageName) {
             synchronized (mLock) {
-                PackageParser.Package pkg = mPackages.get(packageName);
+                AndroidPackage pkg = mPackages.get(packageName);
                 return pkg != null
-                        ? ((pkg.applicationInfo.flags&(ApplicationInfo.FLAG_SYSTEM
+                        ? ((pkg.getFlags() & (ApplicationInfo.FLAG_SYSTEM
                                         | ApplicationInfo.FLAG_PERSISTENT)) ==
                                 (ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_PERSISTENT))
                         : false;
@@ -23380,9 +22963,9 @@
         }
 
         @Override
-        public boolean isLegacySystemApp(PackageParser.Package pkg) {
+        public boolean isLegacySystemApp(AndroidPackage pkg) {
             synchronized (mLock) {
-                final PackageSetting ps = (PackageSetting) pkg.mExtras;
+                final PackageSetting ps = getPackageSetting(pkg.getPackageName());
                 return mPromoteSystemApps
                         && ps.isSystem()
                         && mExistingSystemPackages.contains(ps.name);
@@ -23393,9 +22976,10 @@
         public List<PackageInfo> getOverlayPackages(int userId) {
             final ArrayList<PackageInfo> overlayPackages = new ArrayList<PackageInfo>();
             synchronized (mLock) {
-                for (PackageParser.Package p : mPackages.values()) {
-                    if (p.mOverlayTarget != null) {
-                        PackageInfo pkg = generatePackageInfo((PackageSetting)p.mExtras, 0, userId);
+                for (AndroidPackage p : mPackages.values()) {
+                    if (p.getOverlayTarget() != null) {
+                        PackageInfo pkg = generatePackageInfo(getPackageSetting(p.getPackageName()),
+                                0, userId);
                         if (pkg != null) {
                             overlayPackages.add(pkg);
                         }
@@ -23409,9 +22993,9 @@
         public List<String> getTargetPackageNames(int userId) {
             List<String> targetPackages = new ArrayList<>();
             synchronized (mLock) {
-                for (PackageParser.Package p : mPackages.values()) {
-                    if (p.mOverlayTarget == null) {
-                        targetPackages.add(p.packageName);
+                for (AndroidPackage p : mPackages.values()) {
+                    if (p.getOverlayTarget() == null) {
+                        targetPackages.add(p.getPackageName());
                     }
                 }
             }
@@ -23432,12 +23016,12 @@
                     overlayPaths = new ArrayList<>(N);
                     for (int i = 0; i < N; i++) {
                         final String packageName = overlayPackageNames.get(i);
-                        final PackageParser.Package pkg = mPackages.get(packageName);
+                        final AndroidPackage pkg = mPackages.get(packageName);
                         if (pkg == null) {
                             Slog.e(TAG, "failed to find package " + packageName);
                             return false;
                         }
-                        overlayPaths.add(pkg.baseCodePath);
+                        overlayPaths.add(pkg.getBaseCodePath());
                     }
                 }
 
@@ -23555,12 +23139,12 @@
         }
 
         @Override
-        public void forEachPackage(Consumer<PackageParser.Package> actionLocked) {
+        public void forEachPackage(Consumer<AndroidPackage> actionLocked) {
             PackageManagerService.this.forEachPackage(actionLocked);
         }
 
         @Override
-        public void forEachInstalledPackage(@NonNull Consumer<PackageParser.Package> actionLocked,
+        public void forEachInstalledPackage(@NonNull Consumer<AndroidPackage> actionLocked,
                 @UserIdInt int userId) {
             PackageManagerService.this.forEachInstalledPackage(actionLocked, userId);
         }
@@ -23609,7 +23193,7 @@
          */
         @Override
         public boolean compileLayouts(String packageName) {
-            PackageParser.Package pkg;
+            AndroidPackage pkg;
             synchronized (mLock) {
                 pkg = mPackages.get(packageName);
                 if (pkg == null) {
@@ -23716,12 +23300,12 @@
 
         @Override
         public boolean isCallerInstallerOfRecord(
-                @NonNull PackageParser.Package pkg, int callingUid) {
+                @NonNull AndroidPackage pkg, int callingUid) {
             synchronized (mLock) {
                 if (pkg == null) {
                     return false;
                 }
-                final PackageSetting packageSetting = (PackageSetting) pkg.mExtras;
+                final PackageSetting packageSetting = getPackageSetting(pkg.getPackageName());
                 if (packageSetting == null) {
                     return false;
                 }
@@ -23818,7 +23402,16 @@
         }
     }
 
-    void forEachPackage(Consumer<PackageParser.Package> actionLocked) {
+    @Nullable
+    public PackageSetting getPackageSetting(String packageName) {
+        synchronized (mPackages) {
+            packageName = resolveInternalPackageNameLPr(
+                    packageName, PackageManager.VERSION_CODE_HIGHEST);
+            return mSettings.mPackages.get(packageName);
+        }
+    }
+
+    void forEachPackage(Consumer<AndroidPackage> actionLocked) {
         synchronized (mLock) {
             int numPackages = mPackages.size();
             for (int i = 0; i < numPackages; i++) {
@@ -23827,13 +23420,13 @@
         }
     }
 
-    void forEachInstalledPackage(@NonNull Consumer<PackageParser.Package> actionLocked,
+    void forEachInstalledPackage(@NonNull Consumer<AndroidPackage> actionLocked,
             @UserIdInt int userId) {
         synchronized (mLock) {
             int numPackages = mPackages.size();
             for (int i = 0; i < numPackages; i++) {
-                PackageParser.Package pkg = mPackages.valueAt(i);
-                PackageSetting setting = mSettings.getPackageLPr(pkg.packageName);
+                AndroidPackage pkg = mPackages.valueAt(i);
+                PackageSetting setting = mSettings.getPackageLPr(pkg.getPackageName());
                 if (setting == null || !setting.getInstalled(userId)) {
                     continue;
                 }
@@ -23850,7 +23443,7 @@
      * Return a <b>copy</b> of the collection of packages known to the package manager.
      * @return A copy of the values of mPackages.
      */
-    Collection<PackageParser.Package> getPackages() {
+    Collection<AndroidPackage> getPackages() {
         synchronized (mLock) {
             return new ArrayList<>(mPackages.values());
         }
@@ -23886,8 +23479,8 @@
         return mCompilerStats.getPackageStats(pkgName);
     }
 
-    public CompilerStats.PackageStats getOrCreateCompilerPackageStats(PackageParser.Package pkg) {
-        return getOrCreateCompilerPackageStats(pkg.packageName);
+    public CompilerStats.PackageStats getOrCreateCompilerPackageStats(AndroidPackage pkg) {
+        return getOrCreateCompilerPackageStats(pkg.getPackageName());
     }
 
     public CompilerStats.PackageStats getOrCreateCompilerPackageStats(String pkgName) {
@@ -23997,7 +23590,7 @@
 
     boolean canHaveOatDir(String packageName) {
         synchronized (mLock) {
-            PackageParser.Package p = mPackages.get(packageName);
+            AndroidPackage p = mPackages.get(packageName);
             if (p == null) {
                 return false;
             }
@@ -24005,11 +23598,11 @@
         }
     }
 
-    private String getOatDir(PackageParser.Package pkg) {
+    private String getOatDir(AndroidPackage pkg) {
         if (!pkg.canHaveOatDir()) {
             return null;
         }
-        File codePath = new File(pkg.codePath);
+        File codePath = new File(pkg.getCodePath());
         if (codePath.isDirectory()) {
             return PackageDexOptimizer.getOatDir(codePath).getAbsolutePath();
         }
@@ -24020,11 +23613,12 @@
         final String[] instructionSets;
         final List<String> codePaths;
         final String oatDir;
-        final PackageParser.Package pkg;
+        final AndroidPackage pkg;
         synchronized (mLock) {
             pkg = mPackages.get(packageName);
         }
-        instructionSets = getAppDexInstructionSets(pkg.applicationInfo);
+        instructionSets = getAppDexInstructionSets(pkg.getPrimaryCpuAbi(),
+                pkg.getSecondaryCpuAbi());
         codePaths = pkg.getAllCodePaths();
         oatDir = getOatDir(pkg);
 
@@ -24043,19 +23637,19 @@
         Set<String> unusedPackages = new HashSet<>();
         long currentTimeInMillis = System.currentTimeMillis();
         synchronized (mLock) {
-            for (PackageParser.Package pkg : mPackages.values()) {
-                PackageSetting ps =  mSettings.mPackages.get(pkg.packageName);
+            for (AndroidPackage pkg : mPackages.values()) {
+                PackageSetting ps =  mSettings.mPackages.get(pkg.getPackageName());
                 if (ps == null) {
                     continue;
                 }
                 PackageDexUsage.PackageUseInfo packageUseInfo =
-                      getDexManager().getPackageUseInfoOrDefault(pkg.packageName);
+                      getDexManager().getPackageUseInfoOrDefault(pkg.getPackageName());
                 if (PackageManagerServiceUtils
                         .isUnusedSinceTimeInMillis(ps.firstInstallTime, currentTimeInMillis,
                                 downgradeTimeThresholdMillis, packageUseInfo,
                                 pkg.getLatestPackageUseTimeInMills(),
                                 pkg.getLatestForegroundPackageUseTimeInMills())) {
-                    unusedPackages.add(pkg.packageName);
+                    unusedPackages.add(pkg.getPackageName());
                 }
             }
         }
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index ef47410..ded9a9c 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -35,10 +35,13 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfoLite;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
 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.AndroidPackage;
+import android.content.pm.parsing.ApkParseUtils;
 import android.os.Build;
 import android.os.Debug;
 import android.os.Environment;
@@ -120,7 +123,7 @@
     // Sort a list of apps by their last usage, most recently used apps first. The order of
     // packages without usage data is undefined (but they will be sorted after the packages
     // that do have usage data).
-    public static void sortPackagesByUsageDate(List<PackageParser.Package> pkgs,
+    public static void sortPackagesByUsageDate(List<AndroidPackage> pkgs,
             PackageManagerService packageManagerService) {
         if (!packageManagerService.isHistoricalPackageUsageAvailable()) {
             return;
@@ -135,12 +138,12 @@
     // package will be removed from {@code packages} and added to {@code result} with its
     // dependencies. If usage data is available, the positive packages will be sorted by usage
     // data (with {@code sortTemp} as temporary storage).
-    private static void applyPackageFilter(Predicate<PackageParser.Package> filter,
-            Collection<PackageParser.Package> result,
-            Collection<PackageParser.Package> packages,
-            @NonNull List<PackageParser.Package> sortTemp,
+    private static void applyPackageFilter(Predicate<AndroidPackage> filter,
+            Collection<AndroidPackage> result,
+            Collection<AndroidPackage> packages,
+            @NonNull List<AndroidPackage> sortTemp,
             PackageManagerService packageManagerService) {
-        for (PackageParser.Package pkg : packages) {
+        for (AndroidPackage pkg : packages) {
             if (filter.test(pkg)) {
                 sortTemp.add(pkg);
             }
@@ -149,10 +152,10 @@
         sortPackagesByUsageDate(sortTemp, packageManagerService);
         packages.removeAll(sortTemp);
 
-        for (PackageParser.Package pkg : sortTemp) {
+        for (AndroidPackage pkg : sortTemp) {
             result.add(pkg);
 
-            Collection<PackageParser.Package> deps =
+            Collection<AndroidPackage> deps =
                     packageManagerService.findSharedNonSystemLibraries(pkg);
             if (!deps.isEmpty()) {
                 deps.removeAll(result);
@@ -166,50 +169,51 @@
 
     // Sort apps by importance for dexopt ordering. Important apps are given
     // more priority in case the device runs out of space.
-    public static List<PackageParser.Package> getPackagesForDexopt(
-            Collection<PackageParser.Package> packages,
+    public static List<AndroidPackage> getPackagesForDexopt(
+            Collection<AndroidPackage> packages,
             PackageManagerService packageManagerService) {
         return getPackagesForDexopt(packages, packageManagerService, DEBUG_DEXOPT);
     }
 
-    public static List<PackageParser.Package> getPackagesForDexopt(
-            Collection<PackageParser.Package> packages,
+    public static List<AndroidPackage> getPackagesForDexopt(
+            Collection<AndroidPackage> packages,
             PackageManagerService packageManagerService,
             boolean debug) {
-        ArrayList<PackageParser.Package> remainingPkgs = new ArrayList<>(packages);
-        LinkedList<PackageParser.Package> result = new LinkedList<>();
-        ArrayList<PackageParser.Package> sortTemp = new ArrayList<>(remainingPkgs.size());
+        ArrayList<AndroidPackage> remainingPkgs = new ArrayList<>(packages);
+        LinkedList<AndroidPackage> result = new LinkedList<>();
+        ArrayList<AndroidPackage> sortTemp = new ArrayList<>(remainingPkgs.size());
 
         // Give priority to core apps.
-        applyPackageFilter((pkg) -> pkg.coreApp, result, remainingPkgs, sortTemp,
+        applyPackageFilter((pkg) -> pkg.isCoreApp(), result, remainingPkgs, sortTemp,
                 packageManagerService);
 
         // Give priority to system apps that listen for pre boot complete.
         Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
         final ArraySet<String> pkgNames = getPackageNamesForIntent(intent, UserHandle.USER_SYSTEM);
-        applyPackageFilter((pkg) -> pkgNames.contains(pkg.packageName), result, remainingPkgs,
+        applyPackageFilter((pkg) -> pkgNames.contains(pkg.getPackageName()), result, remainingPkgs,
                 sortTemp, packageManagerService);
 
         // Give priority to apps used by other apps.
         DexManager dexManager = packageManagerService.getDexManager();
         applyPackageFilter((pkg) ->
-                dexManager.getPackageUseInfoOrDefault(pkg.packageName)
+                dexManager.getPackageUseInfoOrDefault(pkg.getPackageName())
                         .isAnyCodePathUsedByOtherApps(),
                 result, remainingPkgs, sortTemp, packageManagerService);
 
         // Filter out packages that aren't recently used, add all remaining apps.
         // TODO: add a property to control this?
-        Predicate<PackageParser.Package> remainingPredicate;
+        Predicate<AndroidPackage> remainingPredicate;
         if (!remainingPkgs.isEmpty() && packageManagerService.isHistoricalPackageUsageAvailable()) {
             if (debug) {
                 Log.i(TAG, "Looking at historical package use");
             }
             // Get the package that was used last.
-            PackageParser.Package lastUsed = Collections.max(remainingPkgs, (pkg1, pkg2) ->
+            AndroidPackage lastUsed = Collections.max(remainingPkgs, (pkg1, pkg2) ->
                     Long.compare(pkg1.getLatestForegroundPackageUseTimeInMills(),
                             pkg2.getLatestForegroundPackageUseTimeInMills()));
             if (debug) {
-                Log.i(TAG, "Taking package " + lastUsed.packageName + " as reference in time use");
+                Log.i(TAG, "Taking package " + lastUsed.getPackageName()
+                        + " as reference in time use");
             }
             long estimatedPreviousSystemUseTime =
                     lastUsed.getLatestForegroundPackageUseTimeInMills();
@@ -285,13 +289,13 @@
         }
     }
 
-    public static String packagesToString(Collection<PackageParser.Package> c) {
+    public static String packagesToString(Collection<AndroidPackage> c) {
         StringBuilder sb = new StringBuilder();
-        for (PackageParser.Package pkg : c) {
+        for (AndroidPackage pkg : c) {
             if (sb.length() > 0) {
                 sb.append(", ");
             }
-            sb.append(pkg.packageName);
+            sb.append(pkg.getPackageName());
         }
         return sb.toString();
     }
@@ -309,16 +313,16 @@
         return false;
     }
 
-    public static long getLastModifiedTime(PackageParser.Package pkg) {
-        final File srcFile = new File(pkg.codePath);
+    public static long getLastModifiedTime(AndroidPackage pkg) {
+        final File srcFile = new File(pkg.getCodePath());
         if (!srcFile.isDirectory()) {
             return srcFile.lastModified();
         }
-        final File baseFile = new File(pkg.baseCodePath);
+        final File baseFile = new File(pkg.getBaseCodePath());
         long maxModifiedTime = baseFile.lastModified();
-        if (pkg.splitCodePaths != null) {
-            for (int i = pkg.splitCodePaths.length - 1; i >=0; --i) {
-                final File splitFile = new File(pkg.splitCodePaths[i]);
+        if (pkg.getSplitCodePaths() != null) {
+            for (int i = pkg.getSplitCodePaths().length - 1; i >=0; --i) {
+                final File splitFile = new File(pkg.getSplitCodePaths()[i]);
                 maxModifiedTime = Math.max(maxModifiedTime, splitFile.lastModified());
             }
         }
@@ -539,7 +543,7 @@
     private static boolean matchSignatureInSystem(PackageSetting pkgSetting,
             PackageSetting disabledPkgSetting) {
         try {
-            PackageParser.collectCertificates(disabledPkgSetting.pkg, true /* skipVerify */);
+            ApkParseUtils.collectCertificates(disabledPkgSetting.pkg, true /* skipVerify */);
             if (pkgSetting.signatures.mSigningDetails.checkCapability(
                     disabledPkgSetting.signatures.mSigningDetails,
                     PackageParser.SigningDetails.CertCapabilities.INSTALLED_DATA)
@@ -905,8 +909,10 @@
      * Returns the {@link PermissionsState} for the given package. If the {@link PermissionsState}
      * could not be found, {@code null} will be returned.
      */
-    public static PermissionsState getPermissionsState(PackageParser.Package pkg) {
-        final PackageSetting packageSetting = (PackageSetting) pkg.mExtras;
+    public static PermissionsState getPermissionsState(
+            PackageManagerInternal packageManagerInternal, AndroidPackage pkg) {
+        final PackageSetting packageSetting =
+                (PackageSetting) packageManagerInternal.getPackageSetting(pkg.getPackageName());
         if (packageSetting == null) {
             return null;
         }
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index b961096..fff404f 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -48,7 +48,6 @@
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 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;
@@ -62,6 +61,7 @@
 import android.content.pm.dex.ArtManager;
 import android.content.pm.dex.DexMetadataHelper;
 import android.content.pm.dex.ISnapshotRuntimeProfileCallback;
+import android.content.pm.parsing.ApkLiteParseUtils;
 import android.content.res.AssetManager;
 import android.content.res.Resources;
 import android.content.rollback.IRollbackManager;
@@ -453,7 +453,7 @@
                 throw new IllegalArgumentException("Error: Can't open file: " + inPath);
             }
             try {
-                ApkLite baseApk = PackageParser.parseApkLite(fd.getFileDescriptor(), inPath, 0);
+                ApkLite baseApk = ApkLiteParseUtils.parseApkLite(fd.getFileDescriptor(), inPath, 0);
                 PackageLite pkgLite = new PackageLite(null, baseApk, null, null, null, null,
                         null, null);
                 sessionSize += PackageHelper.calculateInstalledSize(pkgLite,
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index d38dd93..bbc0dc9 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -18,8 +18,9 @@
 
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
-import android.content.pm.PackageParser;
 import android.content.pm.UserInfo;
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.ParsedPackage;
 import android.service.pm.PackageProto;
 import android.util.proto.ProtoOutputStream;
 
@@ -31,9 +32,11 @@
 /**
  * Settings data for a particular package we know about.
  */
-public final class PackageSetting extends PackageSettingBase {
+public final class PackageSetting extends PackageSettingBase implements
+        ParsedPackage.PackageSettingCallback {
     int appId;
-    PackageParser.Package pkg;
+
+    public AndroidPackage pkg;
     /**
      * WARNING. The object reference is important. We perform integer equality and NOT
      * object equality to check whether shared user settings are the same.
@@ -50,12 +53,12 @@
     PackageSetting(String name, String realName, File codePath, File resourcePath,
             String legacyNativeLibraryPathString, String primaryCpuAbiString,
             String secondaryCpuAbiString, String cpuAbiOverrideString,
-            long pVersionCode, int pkgFlags, int privateFlags, String parentPackageName,
-            List<String> childPackageNames, int sharedUserId, String[] usesStaticLibraries,
+            long pVersionCode, int pkgFlags, int privateFlags,
+            int sharedUserId, String[] usesStaticLibraries,
             long[] usesStaticLibrariesVersions) {
         super(name, realName, codePath, resourcePath, legacyNativeLibraryPathString,
                 primaryCpuAbiString, secondaryCpuAbiString, cpuAbiOverrideString,
-                pVersionCode, pkgFlags, privateFlags, parentPackageName, childPackageNames,
+                pVersionCode, pkgFlags, privateFlags,
                 usesStaticLibraries, usesStaticLibrariesVersions);
         this.sharedUserId = sharedUserId;
     }
@@ -116,10 +119,6 @@
                 : super.getPermissionsState();
     }
 
-    public PackageParser.Package getPackage() {
-        return pkg;
-    }
-
     public int getAppId() {
         return appId;
     }
@@ -132,6 +131,7 @@
         return installPermissionsFixed;
     }
 
+    // TODO(b/135203078): Remove these in favor of reading from the package directly
     public boolean isPrivileged() {
         return (pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
     }
@@ -176,10 +176,6 @@
         return true;
     }
 
-    public boolean hasChildPackages() {
-        return childPackageNames != null && !childPackageNames.isEmpty();
-    }
-
     public void dumpDebug(ProtoOutputStream proto, long fieldId, List<UserInfo> users) {
         final long packageToken = proto.start(fieldId);
         proto.write(PackageProto.NAME, (realName != null ? realName : name));
@@ -190,18 +186,19 @@
         proto.write(PackageProto.INSTALLER_NAME, installSource.installerPackageName);
 
         if (pkg != null) {
-            proto.write(PackageProto.VERSION_STRING, pkg.mVersionName);
+            proto.write(PackageProto.VERSION_STRING, pkg.getVersionName());
 
             long splitToken = proto.start(PackageProto.SPLITS);
             proto.write(PackageProto.SplitProto.NAME, "base");
-            proto.write(PackageProto.SplitProto.REVISION_CODE, pkg.baseRevisionCode);
+            proto.write(PackageProto.SplitProto.REVISION_CODE, pkg.getBaseRevisionCode());
             proto.end(splitToken);
 
-            if (pkg.splitNames != null) {
-                for (int i = 0; i < pkg.splitNames.length; i++) {
+            if (pkg.getSplitNames() != null) {
+                for (int i = 0; i < pkg.getSplitNames().length; i++) {
                     splitToken = proto.start(PackageProto.SPLITS);
-                    proto.write(PackageProto.SplitProto.NAME, pkg.splitNames[i]);
-                    proto.write(PackageProto.SplitProto.REVISION_CODE, pkg.splitRevisionCodes[i]);
+                    proto.write(PackageProto.SplitProto.NAME, pkg.getSplitNames()[i]);
+                    proto.write(PackageProto.SplitProto.REVISION_CODE,
+                            pkg.getSplitRevisionCodes()[i]);
                     proto.end(splitToken);
                 }
             }
@@ -225,4 +222,10 @@
         sharedUserId = other.sharedUserId;
         sharedUser = other.sharedUser;
     }
+
+    // TODO(b/135203078): Move to constructor
+    @Override
+    public void setAndroidPackage(AndroidPackage pkg) {
+        this.pkg = pkg;
+    }
 }
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index 45ab357..671450d7 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -39,7 +39,6 @@
 import com.android.internal.util.Preconditions;
 
 import java.io.File;
-import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Set;
@@ -54,9 +53,6 @@
     public final String name;
     final String realName;
 
-    String parentPackageName;
-    List<String> childPackageNames;
-
     /**
      * Path where this package was found on disk. For monolithic packages
      * this is path to single base APK file; for cluster packages this is
@@ -138,14 +134,10 @@
             String legacyNativeLibraryPathString, String primaryCpuAbiString,
             String secondaryCpuAbiString, String cpuAbiOverrideString,
             long pVersionCode, int pkgFlags, int pkgPrivateFlags,
-            String parentPackageName, List<String> childPackageNames,
             String[] usesStaticLibraries, long[] usesStaticLibrariesVersions) {
         super(pkgFlags, pkgPrivateFlags);
         this.name = name;
         this.realName = realName;
-        this.parentPackageName = parentPackageName;
-        this.childPackageNames = (childPackageNames != null)
-                ? new ArrayList<>(childPackageNames) : null;
         this.usesStaticLibraries = usesStaticLibraries;
         this.usesStaticLibrariesVersions = usesStaticLibrariesVersions;
         this.codePath = codePath;
@@ -235,8 +227,6 @@
     }
 
     private void doCopy(PackageSettingBase orig) {
-        childPackageNames = (orig.childPackageNames != null)
-                ? new ArrayList<>(orig.childPackageNames) : null;
         codePath = orig.codePath;
         codePathString = orig.codePathString;
         cpuAbiOverrideString = orig.cpuAbiOverrideString;
@@ -247,7 +237,6 @@
         lastUpdateTime = orig.lastUpdateTime;
         legacyNativeLibraryPathString = orig.legacyNativeLibraryPathString;
         // Intentionally skip mOldCodePaths; it's not relevant for copies
-        parentPackageName = orig.parentPackageName;
         primaryCpuAbiString = orig.primaryCpuAbiString;
         resourcePath = orig.resourcePath;
         resourcePathString = orig.resourcePathString;
@@ -670,8 +659,6 @@
 
     protected PackageSettingBase updateFrom(PackageSettingBase other) {
         super.copyFrom(other);
-        this.parentPackageName = other.parentPackageName;
-        this.childPackageNames = other.childPackageNames;
         this.codePath = other.codePath;
         this.codePathString = other.codePathString;
         this.resourcePath = other.resourcePath;
diff --git a/services/core/java/com/android/server/pm/PackageUsage.java b/services/core/java/com/android/server/pm/PackageUsage.java
index ac1f739..ce2c9e7 100644
--- a/services/core/java/com/android/server/pm/PackageUsage.java
+++ b/services/core/java/com/android/server/pm/PackageUsage.java
@@ -20,7 +20,7 @@
 import static android.os.Process.SYSTEM_UID;
 
 import android.content.pm.PackageManager;
-import android.content.pm.PackageParser;
+import android.content.pm.parsing.AndroidPackage;
 import android.os.FileUtils;
 import android.util.AtomicFile;
 import android.util.Log;
@@ -36,7 +36,7 @@
 import java.nio.charset.StandardCharsets;
 import java.util.Map;
 
-class PackageUsage extends AbstractStatsBase<Map<String, PackageParser.Package>> {
+class PackageUsage extends AbstractStatsBase<Map<String, AndroidPackage>> {
 
     private static final String USAGE_FILE_MAGIC = "PACKAGE_USAGE__VERSION_";
     private static final String USAGE_FILE_MAGIC_VERSION_1 = USAGE_FILE_MAGIC + "1";
@@ -52,7 +52,7 @@
     }
 
     @Override
-    protected void writeInternal(Map<String, PackageParser.Package> packages) {
+    protected void writeInternal(Map<String, AndroidPackage> packages) {
         AtomicFile file = getFile();
         FileOutputStream f = null;
         try {
@@ -66,13 +66,13 @@
             sb.append('\n');
             out.write(sb.toString().getBytes(StandardCharsets.US_ASCII));
 
-            for (PackageParser.Package pkg : packages.values()) {
+            for (AndroidPackage pkg : packages.values()) {
                 if (pkg.getLatestPackageUseTimeInMills() == 0L) {
                     continue;
                 }
                 sb.setLength(0);
-                sb.append(pkg.packageName);
-                for (long usageTimeInMillis : pkg.mLastPackageUsageTimeInMills) {
+                sb.append(pkg.getPackageName());
+                for (long usageTimeInMillis : pkg.getLastPackageUsageTimeInMills()) {
                     sb.append(' ');
                     sb.append(usageTimeInMillis);
                 }
@@ -90,7 +90,7 @@
     }
 
     @Override
-    protected void readInternal(Map<String, PackageParser.Package> packages) {
+    protected void readInternal(Map<String, AndroidPackage> packages) {
         AtomicFile file = getFile();
         BufferedInputStream in = null;
         try {
@@ -114,7 +114,7 @@
         }
     }
 
-    private void readVersion0LP(Map<String, PackageParser.Package> packages, InputStream in,
+    private void readVersion0LP(Map<String, AndroidPackage> packages, InputStream in,
             StringBuffer sb, String firstLine)
             throws IOException {
         // Initial version of the file had no version number and stored one
@@ -128,7 +128,7 @@
             }
 
             String packageName = tokens[0];
-            PackageParser.Package pkg = packages.get(packageName);
+            AndroidPackage pkg = packages.get(packageName);
             if (pkg == null) {
                 continue;
             }
@@ -137,12 +137,12 @@
             for (int reason = 0;
                     reason < PackageManager.NOTIFY_PACKAGE_USE_REASONS_COUNT;
                     reason++) {
-                pkg.mLastPackageUsageTimeInMills[reason] = timestamp;
+                pkg.mutate().setLastPackageUsageTimeInMills(reason, timestamp);
             }
         }
     }
 
-    private void readVersion1LP(Map<String, PackageParser.Package> packages, InputStream in,
+    private void readVersion1LP(Map<String, AndroidPackage> packages, InputStream in,
             StringBuffer sb) throws IOException {
         // Version 1 of the file started with the corresponding version
         // number and then stored a package name and eight timestamps per line.
@@ -154,7 +154,7 @@
             }
 
             String packageName = tokens[0];
-            PackageParser.Package pkg = packages.get(packageName);
+            AndroidPackage pkg = packages.get(packageName);
             if (pkg == null) {
                 continue;
             }
@@ -162,7 +162,8 @@
             for (int reason = 0;
                     reason < PackageManager.NOTIFY_PACKAGE_USE_REASONS_COUNT;
                     reason++) {
-                pkg.mLastPackageUsageTimeInMills[reason] = parseAsLong(tokens[reason + 1]);
+                pkg.mutate().setLastPackageUsageTimeInMills(reason,
+                        parseAsLong(tokens[reason + 1]));
             }
         }
     }
@@ -196,4 +197,4 @@
             sb.append((char)ch);
         }
     }
-}
\ No newline at end of file
+}
diff --git a/services/core/java/com/android/server/pm/ParallelPackageParser.java b/services/core/java/com/android/server/pm/ParallelPackageParser.java
index 4ff3e12..a506514 100644
--- a/services/core/java/com/android/server/pm/ParallelPackageParser.java
+++ b/services/core/java/com/android/server/pm/ParallelPackageParser.java
@@ -16,7 +16,10 @@
 
 package com.android.server.pm;
 
+import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
+
 import android.content.pm.PackageParser;
+import android.content.pm.parsing.ParsedPackage;
 import android.os.Process;
 import android.os.Trace;
 import android.util.DisplayMetrics;
@@ -30,8 +33,6 @@
 import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.ExecutorService;
 
-import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
-
 /**
  * Helper class for parallel parsing of packages using {@link PackageParser}.
  * <p>Parsing requests are processed by a thread-pool of {@link #MAX_THREADS}.
@@ -65,14 +66,14 @@
 
     static class ParseResult {
 
-        PackageParser.Package pkg; // Parsed package
+        ParsedPackage parsedPackage; // Parsed package
         File scanFile; // File that was parsed
         Throwable throwable; // Set if an error occurs during parsing
 
         @Override
         public String toString() {
             return "ParseResult{" +
-                    "pkg=" + pkg +
+                    "parsedPackage=" + parsedPackage +
                     ", scanFile=" + scanFile +
                     ", throwable=" + throwable +
                     '}';
@@ -100,7 +101,7 @@
     /**
      * Submits the file for parsing
      * @param scanFile file to scan
-     * @param parseFlags parse falgs
+     * @param parseFlags parse flags
      */
     public void submit(File scanFile, int parseFlags) {
         mService.submit(() -> {
@@ -114,7 +115,7 @@
                 pp.setCacheDir(mCacheDir);
                 pp.setCallback(mPackageParserCallback);
                 pr.scanFile = scanFile;
-                pr.pkg = parsePackage(pp, scanFile, parseFlags);
+                pr.parsedPackage = parsePackage(pp, scanFile, parseFlags);
             } catch (Throwable e) {
                 pr.throwable = e;
             } finally {
@@ -133,9 +134,9 @@
     }
 
     @VisibleForTesting
-    protected PackageParser.Package parsePackage(PackageParser packageParser, File scanFile,
+    protected ParsedPackage parsePackage(PackageParser packageParser, File scanFile,
             int parseFlags) throws PackageParser.PackageParserException {
-        return packageParser.parsePackage(scanFile, parseFlags, true /* useCaches */);
+        return packageParser.parseParsedPackage(scanFile, parseFlags, true);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/pm/SELinuxMMAC.java b/services/core/java/com/android/server/pm/SELinuxMMAC.java
index d20f20f..f4076fd 100644
--- a/services/core/java/com/android/server/pm/SELinuxMMAC.java
+++ b/services/core/java/com/android/server/pm/SELinuxMMAC.java
@@ -21,6 +21,7 @@
 import android.content.pm.PackageParser;
 import android.content.pm.PackageParser.SigningDetails;
 import android.content.pm.Signature;
+import android.content.pm.parsing.AndroidPackage;
 import android.os.Environment;
 import android.util.Slog;
 import android.util.Xml;
@@ -391,7 +392,7 @@
      *        MINIMUM_TARGETSDKVERSION.
      * @return String representing the resulting seinfo.
      */
-    public static String getSeInfo(PackageParser.Package pkg, boolean isPrivileged,
+    public static String getSeInfo(AndroidPackage pkg, boolean isPrivileged,
             int targetSdkVersion) {
         String seInfo = null;
         synchronized (sPolicies) {
@@ -420,8 +421,8 @@
         seInfo += TARGETSDKVERSION_STR + targetSdkVersion;
 
         if (DEBUG_POLICY_INSTALL) {
-            Slog.i(TAG, "package (" + pkg.packageName + ") labeled with " +
-                    "seinfo=" + seInfo);
+            Slog.i(TAG, "package (" + pkg.getPackageName() + ") labeled with "
+                    + "seinfo=" + seInfo);
         }
         return seInfo;
     }
@@ -430,7 +431,7 @@
 /**
  * Holds valid policy representations of individual stanzas from a mac_permissions.xml
  * file. Each instance can further be used to assign seinfo values to apks using the
- * {@link Policy#getMatchedSeinfo} method. To create an instance of this use the
+ * {@link Policy#getMatchedSeInfo(AndroidPackage)} method. To create an instance of this use the
  * {@link PolicyBuilder} pattern class, where each instance is validated against a set
  * of invariants before being built and returned. Each instance can be guaranteed to
  * hold one valid policy stanza as outlined in the system/sepolicy/mac_permissions.xml
@@ -557,21 +558,21 @@
      * @return A string representing the seinfo matched during policy lookup.
      *         A value of null can also be returned if no match occured.
      */
-    public String getMatchedSeInfo(PackageParser.Package pkg) {
+    public String getMatchedSeInfo(AndroidPackage pkg) {
         // Check for exact signature matches across all certs.
         Signature[] certs = mCerts.toArray(new Signature[0]);
-        if (pkg.mSigningDetails != SigningDetails.UNKNOWN
-                && !Signature.areExactMatch(certs, pkg.mSigningDetails.signatures)) {
+        if (pkg.getSigningDetails() != SigningDetails.UNKNOWN
+                && !Signature.areExactMatch(certs, pkg.getSigningDetails().signatures)) {
 
             // certs aren't exact match, but the package may have rotated from the known system cert
-            if (certs.length > 1 || !pkg.mSigningDetails.hasCertificate(certs[0])) {
+            if (certs.length > 1 || !pkg.getSigningDetails().hasCertificate(certs[0])) {
                 return null;
             }
         }
 
         // Check for inner package name matches given that the
         // signature checks already passed.
-        String seinfoValue = mPkgMap.get(pkg.packageName);
+        String seinfoValue = mPkgMap.get(pkg.getPackageName());
         if (seinfoValue != null) {
             return seinfoValue;
         }
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 1082eaa..40ad095 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -42,7 +42,6 @@
 import android.content.pm.IntentFilterVerificationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
-import android.content.pm.PackageParser;
 import android.content.pm.PackageUserState;
 import android.content.pm.PermissionInfo;
 import android.content.pm.ResolveInfo;
@@ -50,6 +49,10 @@
 import android.content.pm.SuspendDialogInfo;
 import android.content.pm.UserInfo;
 import android.content.pm.VerifierDeviceIdentity;
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.ComponentParseUtils;
+import android.content.pm.parsing.ComponentParseUtils.ParsedComponent;
+import android.content.pm.parsing.ComponentParseUtils.ParsedPermission;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Build;
@@ -479,8 +482,8 @@
         final PackageSetting dp = mDisabledSysPackages.get(name);
         // always make sure the system package code and resource paths dont change
         if (dp == null && p.pkg != null && p.pkg.isSystem() && !p.pkg.isUpdatedSystemApp()) {
-            if((p.pkg != null) && (p.pkg.applicationInfo != null)) {
-                p.pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
+            if(p.pkg != null) {
+                p.pkg.mutate().setUpdatedSystemApp(true);
             }
             final PackageSetting disabled;
             if (replaced) {
@@ -506,14 +509,14 @@
             return null;
         }
         // Reset flag in ApplicationInfo object
-        if((p.pkg != null) && (p.pkg.applicationInfo != null)) {
-            p.pkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
+        if(p.pkg != null) {
+            p.pkg.mutate().setUpdatedSystemApp(false);
         }
         PackageSetting ret = addPackageLPw(name, p.realName, p.codePath, p.resourcePath,
                 p.legacyNativeLibraryPathString, p.primaryCpuAbiString,
                 p.secondaryCpuAbiString, p.cpuAbiOverrideString,
                 p.appId, p.versionCode, p.pkgFlags, p.pkgPrivateFlags,
-                p.parentPackageName, p.childPackageNames, p.usesStaticLibraries,
+                p.usesStaticLibraries,
                 p.usesStaticLibrariesVersions);
         mDisabledSysPackages.remove(name);
         return ret;
@@ -530,8 +533,7 @@
     PackageSetting addPackageLPw(String name, String realName, File codePath, File resourcePath,
             String legacyNativeLibraryPathString, String primaryCpuAbiString,
             String secondaryCpuAbiString, String cpuAbiOverrideString, int uid, long vc, int
-            pkgFlags, int pkgPrivateFlags, String parentPackageName,
-            List<String> childPackageNames, String[] usesStaticLibraries,
+            pkgFlags, int pkgPrivateFlags, String[] usesStaticLibraries,
             long[] usesStaticLibraryNames) {
         PackageSetting p = mPackages.get(name);
         if (p != null) {
@@ -544,8 +546,8 @@
         }
         p = new PackageSetting(name, realName, codePath, resourcePath,
                 legacyNativeLibraryPathString, primaryCpuAbiString, secondaryCpuAbiString,
-                cpuAbiOverrideString, vc, pkgFlags, pkgPrivateFlags, parentPackageName,
-                childPackageNames, 0 /*userId*/, usesStaticLibraries, usesStaticLibraryNames);
+                cpuAbiOverrideString, vc, pkgFlags, pkgPrivateFlags,
+                0 /*userId*/, usesStaticLibraries, usesStaticLibraryNames);
         p.appId = uid;
         if (registerExistingAppIdLPw(uid, p, name)) {
             mPackages.put(name, p);
@@ -607,19 +609,15 @@
             File codePath, File resourcePath, String legacyNativeLibraryPath, String primaryCpuAbi,
             String secondaryCpuAbi, long versionCode, int pkgFlags, int pkgPrivateFlags,
             UserHandle installUser, boolean allowInstall, boolean instantApp,
-            boolean virtualPreload, String parentPkgName, List<String> childPkgNames,
-            UserManagerService userManager,
+            boolean virtualPreload, UserManagerService userManager,
             String[] usesStaticLibraries, long[] usesStaticLibrariesVersions) {
         final PackageSetting pkgSetting;
         if (originalPkg != null) {
             if (PackageManagerService.DEBUG_UPGRADE) Log.v(PackageManagerService.TAG, "Package "
                     + pkgName + " is adopting original package " + originalPkg.name);
             pkgSetting = new PackageSetting(originalPkg, pkgName /*realPkgName*/);
-            pkgSetting.childPackageNames =
-                    (childPkgNames != null) ? new ArrayList<>(childPkgNames) : null;
             pkgSetting.codePath = codePath;
             pkgSetting.legacyNativeLibraryPathString = legacyNativeLibraryPath;
-            pkgSetting.parentPackageName = parentPkgName;
             pkgSetting.pkgFlags = pkgFlags;
             pkgSetting.pkgPrivateFlags = pkgPrivateFlags;
             pkgSetting.primaryCpuAbiString = primaryCpuAbi;
@@ -637,7 +635,7 @@
             pkgSetting = new PackageSetting(pkgName, realPkgName, codePath, resourcePath,
                     legacyNativeLibraryPath, primaryCpuAbi, secondaryCpuAbi,
                     null /*cpuAbiOverrideString*/, versionCode, pkgFlags, pkgPrivateFlags,
-                    parentPkgName, childPkgNames, 0 /*sharedUserId*/, usesStaticLibraries,
+                    0 /*sharedUserId*/, usesStaticLibraries,
                     usesStaticLibrariesVersions);
             pkgSetting.setTimeStamp(codePath.lastModified());
             pkgSetting.sharedUser = sharedUser;
@@ -721,7 +719,7 @@
             @NonNull File codePath, File resourcePath,
             @Nullable String legacyNativeLibraryPath, @Nullable String primaryCpuAbi,
             @Nullable String secondaryCpuAbi, int pkgFlags, int pkgPrivateFlags,
-            @Nullable List<String> childPkgNames, @NonNull UserManagerService userManager,
+            @NonNull UserManagerService userManager,
             @Nullable String[] usesStaticLibraries, @Nullable long[] usesStaticLibrariesVersions)
                     throws PackageManagerException {
         final String pkgName = pkgSetting.name;
@@ -799,9 +797,6 @@
                 pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_ODM;
         pkgSetting.primaryCpuAbiString = primaryCpuAbi;
         pkgSetting.secondaryCpuAbiString = secondaryCpuAbi;
-        if (childPkgNames != null) {
-            pkgSetting.childPackageNames = new ArrayList<>(childPkgNames);
-        }
         // Update static shared library dependencies if needed
         if (usesStaticLibraries != null && usesStaticLibrariesVersions != null
                 && usesStaticLibraries.length == usesStaticLibrariesVersions.length) {
@@ -870,15 +865,15 @@
 
     // TODO: Move to scanPackageOnlyLI() after verifying signatures are setup correctly
     // by that time.
-    void insertPackageSettingLPw(PackageSetting p, PackageParser.Package pkg) {
+    void insertPackageSettingLPw(PackageSetting p, AndroidPackage pkg) {
         // Update signatures if needed.
         if (p.signatures.mSigningDetails.signatures == null) {
-            p.signatures.mSigningDetails = pkg.mSigningDetails;
+            p.signatures.mSigningDetails = pkg.getSigningDetails();
         }
         // If this app defines a shared user id initialize
         // the shared user signatures as well.
         if (p.sharedUser != null && p.sharedUser.signatures.mSigningDetails.signatures == null) {
-            p.sharedUser.signatures.mSigningDetails = pkg.mSigningDetails;
+            p.sharedUser.signatures.mSigningDetails = pkg.getSigningDetails();
         }
         addPackageSettingLPw(p, p.sharedUser);
     }
@@ -955,7 +950,7 @@
 
         int affectedUserId = UserHandle.USER_NULL;
         // Update permissions
-        for (String eachPerm : deletedPs.pkg.requestedPermissions) {
+        for (String eachPerm : deletedPs.pkg.getRequestedPermissions()) {
             BasePermission bp = mPermissions.getPermission(eachPerm);
             if (bp == null) {
                 continue;
@@ -965,8 +960,8 @@
             boolean used = false;
             for (PackageSetting pkg : sus.packages) {
                 if (pkg.pkg != null
-                        && !pkg.pkg.packageName.equals(deletedPs.pkg.packageName)
-                        && pkg.pkg.requestedPermissions.contains(eachPerm)) {
+                        && !pkg.pkg.getPackageName().equals(deletedPs.pkg.getPackageName())
+                        && pkg.pkg.getRequestedPermissions().contains(eachPerm)) {
                     used = true;
                     break;
                 }
@@ -976,13 +971,13 @@
             }
 
             PermissionsState permissionsState = sus.getPermissionsState();
-            PackageSetting disabledPs = getDisabledSystemPkgLPr(deletedPs.pkg.packageName);
+            PackageSetting disabledPs = getDisabledSystemPkgLPr(deletedPs.pkg.getPackageName());
 
             // If the package is shadowing is a disabled system package,
             // do not drop permissions that the shadowed package requests.
             if (disabledPs != null) {
                 boolean reqByDisabledSysPkg = false;
-                for (String permission : disabledPs.pkg.requestedPermissions) {
+                for (String permission : disabledPs.pkg.getRequestedPermissions()) {
                     if (permission.equals(eachPerm)) {
                         reqByDisabledSysPkg = true;
                         break;
@@ -2215,20 +2210,6 @@
         serializer.endTag(null, TAG_PERMISSIONS);
     }
 
-    void writeChildPackagesLPw(XmlSerializer serializer, List<String> childPackageNames)
-            throws IOException {
-        if (childPackageNames == null) {
-            return;
-        }
-        final int childCount = childPackageNames.size();
-        for (int i = 0; i < childCount; i++) {
-            String childPackageName = childPackageNames.get(i);
-            serializer.startTag(null, TAG_CHILD_PACKAGE);
-            serializer.attribute(null, ATTR_NAME, childPackageName);
-            serializer.endTag(null, TAG_CHILD_PACKAGE);
-        }
-    }
-
     void readUsesStaticLibLPw(XmlPullParser parser, PackageSetting outPs)
             throws IOException, XmlPullParserException {
         int outerDepth = parser.getDepth();
@@ -2682,17 +2663,15 @@
 
             StringBuilder sb = new StringBuilder();
             for (final PackageSetting pkg : mPackages.values()) {
-                if (pkg.pkg == null || pkg.pkg.applicationInfo == null
-                        || pkg.pkg.applicationInfo.dataDir == null) {
+                if (pkg.pkg == null || pkg.pkg.getDataDir() == null) {
                     if (!"android".equals(pkg.name)) {
                         Slog.w(TAG, "Skipping " + pkg + " due to missing metadata");
                     }
                     continue;
                 }
 
-                final ApplicationInfo ai = pkg.pkg.applicationInfo;
-                final String dataPath = ai.dataDir;
-                final boolean isDebug = (ai.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
+                final String dataPath = pkg.pkg.getDataDir();
+                final boolean isDebug = (pkg.pkg.getFlags() & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
                 final int[] gids = pkg.getPermissionsState().computeGids(userIds);
 
                 // Avoid any application that has a space in its path.
@@ -2717,13 +2696,13 @@
                 //   system/core/libpackagelistparser
                 //
                 sb.setLength(0);
-                sb.append(ai.packageName);
+                sb.append(pkg.pkg.getPackageName());
                 sb.append(" ");
-                sb.append(ai.uid);
+                sb.append(pkg.pkg.getUid());
                 sb.append(isDebug ? " 1 " : " 0 ");
                 sb.append(dataPath);
                 sb.append(" ");
-                sb.append(ai.seInfo);
+                sb.append(pkg.pkg.getSeInfo());
                 sb.append(" ");
                 if (gids != null && gids.length > 0) {
                     sb.append(gids[0]);
@@ -2735,9 +2714,9 @@
                     sb.append("none");
                 }
                 sb.append(" ");
-                sb.append(ai.isProfileableByShell() ? "1" : "0");
+                sb.append(pkg.pkg.isProfileableByShell() ? "1" : "0");
                 sb.append(" ");
-                sb.append(String.valueOf(ai.longVersionCode));
+                sb.append(pkg.pkg.getLongVersionCode());
                 sb.append("\n");
                 writer.append(sb);
             }
@@ -2786,12 +2765,6 @@
             serializer.attribute(null, "sharedUserId", Integer.toString(pkg.appId));
         }
 
-        if (pkg.parentPackageName != null) {
-            serializer.attribute(null, "parentPackageName", pkg.parentPackageName);
-        }
-
-        writeChildPackagesLPw(serializer, pkg.childPackageNames);
-
         writeUsesStaticLibLPw(serializer, pkg.usesStaticLibraries, pkg.usesStaticLibrariesVersions);
 
         // If this is a shared user, the permissions will be written there.
@@ -2861,15 +2834,10 @@
         if (pkg.categoryHint != ApplicationInfo.CATEGORY_UNDEFINED) {
             serializer.attribute(null, "categoryHint", Integer.toString(pkg.categoryHint));
         }
-        if (pkg.parentPackageName != null) {
-            serializer.attribute(null, "parentPackageName", pkg.parentPackageName);
-        }
         if (pkg.updateAvailable) {
             serializer.attribute(null, "updateAvailable", "true");
         }
 
-        writeChildPackagesLPw(serializer, pkg.childPackageNames);
-
         writeUsesStaticLibLPw(serializer, pkg.usesStaticLibraries, pkg.usesStaticLibrariesVersions);
 
         pkg.signatures.writeXml(serializer, "sigs", mPastSignatures);
@@ -3161,13 +3129,13 @@
                 LocalServices.getService(PackageManagerInternal.class);
         for (PackageSetting ps : mPackages.values()) {
             if ((ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0 && ps.pkg != null
-                    && ps.pkg.preferredActivityFilters != null) {
-                ArrayList<PackageParser.ActivityIntentInfo> intents
-                        = ps.pkg.preferredActivityFilters;
+                    && ps.pkg.getPreferredActivityFilters() != null) {
+                List<ComponentParseUtils.ParsedActivityIntentInfo> intents
+                        = ps.pkg.getPreferredActivityFilters();
                 for (int i=0; i<intents.size(); i++) {
-                    PackageParser.ActivityIntentInfo aii = intents.get(i);
+                    ComponentParseUtils.ParsedActivityIntentInfo aii = intents.get(i);
                     applyDefaultPreferredActivityLPw(pmInternal, aii, new ComponentName(
-                                    ps.name, aii.activity.className), userId);
+                                    ps.name, aii.getClassName()), userId);
                 }
             }
         }
@@ -3527,7 +3495,7 @@
         PackageSetting ps = new PackageSetting(name, realName, new File(codePathStr),
                 new File(resourcePathStr), legacyNativeLibraryPathStr, primaryCpuAbiStr,
                 secondaryCpuAbiStr, cpuAbiOverrideStr, versionCode, pkgFlags, pkgPrivateFlags,
-                parentPackageName, null /*childPackageNames*/, 0 /*sharedUserId*/, null, null);
+                0 /*sharedUserId*/, null, null);
         String timeStampStr = parser.getAttributeValue(null, "ft");
         if (timeStampStr != null) {
             try {
@@ -3576,12 +3544,6 @@
 
             if (parser.getName().equals(TAG_PERMISSIONS)) {
                 readInstallPermissionsLPr(parser, ps.getPermissionsState());
-            } else if (parser.getName().equals(TAG_CHILD_PACKAGE)) {
-                String childPackageName = parser.getAttributeValue(null, ATTR_NAME);
-                if (ps.childPackageNames == null) {
-                    ps.childPackageNames = new ArrayList<>();
-                }
-                ps.childPackageNames.add(childPackageName);
             } else if (parser.getName().equals(TAG_USES_STATIC_LIB)) {
                 readUsesStaticLibLPw(parser, ps);
             } else {
@@ -3628,7 +3590,6 @@
         PackageSetting packageSetting = null;
         String version = null;
         long versionCode = 0;
-        String parentPackageName;
         try {
             name = parser.getAttributeValue(null, ATTR_NAME);
             realName = parser.getAttributeValue(null, "realName");
@@ -3640,8 +3601,6 @@
 
             legacyCpuAbiString = parser.getAttributeValue(null, "requiredCpuAbi");
 
-            parentPackageName = parser.getAttributeValue(null, "parentPackageName");
-
             legacyNativeLibraryPathStr = parser.getAttributeValue(null, "nativeLibraryPath");
             primaryCpuAbiString = parser.getAttributeValue(null, "primaryCpuAbi");
             secondaryCpuAbiString = parser.getAttributeValue(null, "secondaryCpuAbi");
@@ -3770,7 +3729,7 @@
                 packageSetting = addPackageLPw(name.intern(), realName, new File(codePathStr),
                         new File(resourcePathStr), legacyNativeLibraryPathStr, primaryCpuAbiString,
                         secondaryCpuAbiString, cpuAbiOverrideString, userId, versionCode, pkgFlags,
-                        pkgPrivateFlags, parentPackageName, null /*childPackageNames*/,
+                        pkgPrivateFlags,
                         null /*usesStaticLibraries*/, null /*usesStaticLibraryVersions*/);
                 if (PackageManagerService.DEBUG_SETTINGS)
                     Log.i(PackageManagerService.TAG, "Reading package " + name + ": userId="
@@ -3789,8 +3748,8 @@
                     packageSetting = new PackageSetting(name.intern(), realName, new File(
                             codePathStr), new File(resourcePathStr), legacyNativeLibraryPathStr,
                             primaryCpuAbiString, secondaryCpuAbiString, cpuAbiOverrideString,
-                            versionCode, pkgFlags, pkgPrivateFlags, parentPackageName,
-                            null /*childPackageNames*/, sharedUserId,
+                            versionCode, pkgFlags, pkgPrivateFlags,
+                            sharedUserId,
                             null /*usesStaticLibraries*/, null /*usesStaticLibraryVersions*/);
                     packageSetting.setTimeStamp(timeStamp);
                     packageSetting.firstInstallTime = firstInstallTime;
@@ -3899,12 +3858,6 @@
                     packageSetting.keySetData.addDefinedKeySet(id, alias);
                 } else if (tagName.equals(TAG_DOMAIN_VERIFICATION)) {
                     readDomainVerificationLPw(parser, packageSetting);
-                } else if (tagName.equals(TAG_CHILD_PACKAGE)) {
-                    String childPackageName = parser.getAttributeValue(null, ATTR_NAME);
-                    if (packageSetting.childPackageNames == null) {
-                        packageSetting.childPackageNames = new ArrayList<>();
-                    }
-                    packageSetting.childPackageNames.add(childPackageName);
                 } else {
                     PackageManagerService.reportSettingsProblem(Log.WARN,
                             "Unknown element under <package>: " + parser.getName());
@@ -4057,13 +4010,13 @@
             Iterator<PackageSetting> packagesIterator = packages.iterator();
             for (int i = 0; i < packagesCount; i++) {
                 PackageSetting ps = packagesIterator.next();
-                if (ps.pkg == null || ps.pkg.applicationInfo == null) {
+                if (ps.pkg == null) {
                     continue;
                 }
                 final boolean shouldInstall = ps.isSystem() &&
                         (skipPackageWhitelist || installablePackages.contains(ps.name)) &&
                         !ArrayUtils.contains(disallowedPackages, ps.name) &&
-                        !ps.pkg.applicationInfo.hiddenUntilInstalled;
+                        !ps.pkg.isHiddenUntilInstalled();
                 // Only system apps are initially installed.
                 ps.setInstalled(shouldInstall, userHandle);
                 if (!shouldInstall) {
@@ -4074,8 +4027,8 @@
                 volumeUuids[i] = ps.volumeUuid;
                 names[i] = ps.name;
                 appIds[i] = ps.appId;
-                seinfos[i] = ps.pkg.applicationInfo.seInfo;
-                targetSdkVersions[i] = ps.pkg.applicationInfo.targetSdkVersion;
+                seinfos[i] = ps.pkg.getSeInfo();
+                targetSdkVersions[i] = ps.pkg.getTargetSdkVersion();
             }
         }
         t.traceBegin("createAppData");
@@ -4185,28 +4138,6 @@
         return mVerifierDeviceIdentity;
     }
 
-    boolean hasOtherDisabledSystemPkgWithChildLPr(String parentPackageName,
-            String childPackageName) {
-        final int packageCount = mDisabledSysPackages.size();
-        for (int i = 0; i < packageCount; i++) {
-            PackageSetting disabledPs = mDisabledSysPackages.valueAt(i);
-            if (disabledPs.childPackageNames == null || disabledPs.childPackageNames.isEmpty()) {
-                continue;
-            }
-            if (disabledPs.name.equals(parentPackageName)) {
-                continue;
-            }
-            final int childCount = disabledPs.childPackageNames.size();
-            for (int j = 0; j < childCount; j++) {
-                String currChildPackageName = disabledPs.childPackageNames.get(j);
-                if (currChildPackageName.equals(childPackageName)) {
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
     /**
      * Returns the disabled {@link PackageSetting} for the provided package name if one exists,
      * {@code null} otherwise.
@@ -4229,26 +4160,6 @@
         return getDisabledSystemPkgLPr(enabledPackageSetting.name);
     }
 
-    /**
-     * Fetches an array of the child {@link PackageSetting}s for all child package names referenced
-     * by the provided parent {@link PackageSetting} or {@code null} if no children are referenced.
-     *
-     * Note: Any child packages not found will be null in the returned array.
-     */
-    @Nullable
-    public PackageSetting[] getChildSettingsLPr(PackageSetting parentPackageSetting) {
-        if (parentPackageSetting == null || !parentPackageSetting.hasChildPackages()) {
-            return null;
-        }
-        final int childCount = parentPackageSetting.childPackageNames.size();
-        PackageSetting[] children =
-                new PackageSetting[childCount];
-        for (int i = 0; i < childCount; i++) {
-            children[i] = mPackages.get(parentPackageSetting.childPackageNames.get(i));
-        }
-        return children;
-    }
-
     boolean isEnabledAndMatchLPr(ComponentInfo componentInfo, int flags, int userId) {
         final PackageSetting ps = mPackages.get(componentInfo.packageName);
         if (ps == null) return false;
@@ -4467,6 +4378,7 @@
     void dumpPackageLPr(PrintWriter pw, String prefix, String checkinTag,
             ArraySet<String> permissionNames, PackageSetting ps, SimpleDateFormat sdf,
             Date date, List<UserInfo> users, boolean dumpAll, boolean dumpAllComponents) {
+        AndroidPackage pkg = ps.pkg;
         if (checkinTag != null) {
             pw.print(checkinTag);
             pw.print(",");
@@ -4483,15 +4395,16 @@
             pw.print(ps.installSource.installerPackageName != null
                     ? ps.installSource.installerPackageName : "?");
             pw.println();
-            if (ps.pkg != null) {
+            if (pkg != null) {
                 pw.print(checkinTag); pw.print("-"); pw.print("splt,");
                 pw.print("base,");
-                pw.println(ps.pkg.baseRevisionCode);
-                if (ps.pkg.splitNames != null) {
-                    for (int i = 0; i < ps.pkg.splitNames.length; i++) {
+                pw.println(pkg.getBaseRevisionCode());
+                if (pkg.getSplitNames() != null) {
+                    int[] splitRevisionCodes = pkg.getSplitRevisionCodes();
+                    for (int i = 0; i < pkg.getSplitNames().length; i++) {
                         pw.print(checkinTag); pw.print("-"); pw.print("splt,");
-                        pw.print(ps.pkg.splitNames[i]); pw.print(",");
-                        pw.println(ps.pkg.splitRevisionCodes[i]);
+                        pw.print(pkg.getSplitNames()[i]); pw.print(",");
+                        pw.println(splitRevisionCodes[i]);
                     }
                 }
             }
@@ -4538,7 +4451,7 @@
         if (ps.sharedUser != null) {
             pw.print(prefix); pw.print("  sharedUser="); pw.println(ps.sharedUser);
         }
-        pw.print(prefix); pw.print("  pkg="); pw.println(ps.pkg);
+        pw.print(prefix); pw.print("  pkg="); pw.println(pkg);
         pw.print(prefix); pw.print("  codePath="); pw.println(ps.codePathString);
         if (permissionNames == null) {
             pw.print(prefix); pw.print("  resourcePath="); pw.println(ps.resourcePathString);
@@ -4548,140 +4461,123 @@
             pw.print(prefix); pw.print("  secondaryCpuAbi="); pw.println(ps.secondaryCpuAbiString);
         }
         pw.print(prefix); pw.print("  versionCode="); pw.print(ps.versionCode);
-        if (ps.pkg != null) {
-            pw.print(" minSdk="); pw.print(ps.pkg.applicationInfo.minSdkVersion);
-            pw.print(" targetSdk="); pw.print(ps.pkg.applicationInfo.targetSdkVersion);
+        if (pkg != null) {
+            pw.print(" minSdk="); pw.print(pkg.getMinSdkVersion());
+            pw.print(" targetSdk="); pw.print(pkg.getTargetSdkVersion());
         }
         pw.println();
-        if (ps.pkg != null) {
-            if (ps.pkg.parentPackage != null) {
-                PackageParser.Package parentPkg = ps.pkg.parentPackage;
-                PackageSetting pps = mPackages.get(parentPkg.packageName);
-                if (pps == null || !pps.codePathString.equals(parentPkg.codePath)) {
-                    pps = mDisabledSysPackages.get(parentPkg.packageName);
-                }
-                if (pps != null) {
-                    pw.print(prefix); pw.print("  parentPackage=");
-                    pw.println(pps.realName != null ? pps.realName : pps.name);
-                }
-            } else if (ps.pkg.childPackages != null) {
-                pw.print(prefix); pw.print("  childPackages=[");
-                final int childCount = ps.pkg.childPackages.size();
-                for (int i = 0; i < childCount; i++) {
-                    PackageParser.Package childPkg = ps.pkg.childPackages.get(i);
-                    PackageSetting cps = mPackages.get(childPkg.packageName);
-                    if (cps == null || !cps.codePathString.equals(childPkg.codePath)) {
-                        cps = mDisabledSysPackages.get(childPkg.packageName);
-                    }
-                    if (cps != null) {
-                        if (i > 0) {
-                            pw.print(", ");
-                        }
-                        pw.print(cps.realName != null ? cps.realName : cps.name);
-                    }
-                }
-                pw.println("]");
-            }
-            pw.print(prefix); pw.print("  versionName="); pw.println(ps.pkg.mVersionName);
-            pw.print(prefix); pw.print("  splits="); dumpSplitNames(pw, ps.pkg); pw.println();
-            final int apkSigningVersion = ps.pkg.mSigningDetails.signatureSchemeVersion;
+        if (pkg != null) {
+            pw.print(prefix); pw.print("  versionName="); pw.println(pkg.getVersionName());
+            pw.print(prefix); pw.print("  splits="); dumpSplitNames(pw, pkg); pw.println();
+            final int apkSigningVersion = pkg.getSigningDetails().signatureSchemeVersion;
             pw.print(prefix); pw.print("  apkSigningVersion="); pw.println(apkSigningVersion);
+            // TODO(b/135203078): Is there anything to print here with AppInfo removed?
             pw.print(prefix); pw.print("  applicationInfo=");
-                pw.println(ps.pkg.applicationInfo.toString());
-            pw.print(prefix); pw.print("  flags="); printFlags(pw, ps.pkg.applicationInfo.flags,
+                pw.println(pkg.toAppInfo().toString());
+            pw.print(prefix); pw.print("  flags="); printFlags(pw, pkg.getFlags(),
                     FLAG_DUMP_SPEC); pw.println();
-            if (ps.pkg.applicationInfo.privateFlags != 0) {
+            if (pkg.getPrivateFlags() != 0) {
                 pw.print(prefix); pw.print("  privateFlags="); printFlags(pw,
-                        ps.pkg.applicationInfo.privateFlags, PRIVATE_FLAG_DUMP_SPEC); pw.println();
+                        pkg.getPrivateFlags(), PRIVATE_FLAG_DUMP_SPEC); pw.println();
             }
-            pw.print(prefix); pw.print("  forceQueryable="); pw.println(ps.pkg.mForceQueryable);
-            if (ps.pkg.mQueriesPackages != null) {
-                pw.append(prefix).append("  queriesPackages=").println(ps.pkg.mQueriesPackages);
+            pw.print(prefix); pw.print("  forceQueryable="); pw.println(ps.pkg.isForceQueryable());
+            if (ps.pkg.getQueriesPackages() != null) {
+                pw.append(prefix).append("  queriesPackages=").println(ps.pkg.getQueriesPackages());
             }
-            if (ps.pkg.mQueriesIntents != null) {
-                pw.append(prefix).append("  queriesIntents=").println(ps.pkg.mQueriesIntents);
+            if (ps.pkg.getQueriesIntents() != null) {
+                pw.append(prefix).append("  queriesIntents=").println(ps.pkg.getQueriesIntents());
             }
-            pw.print(prefix); pw.print("  dataDir="); pw.println(ps.pkg.applicationInfo.dataDir);
+            pw.print(prefix); pw.print("  dataDir="); pw.println(ps.pkg.getDataDir());
             pw.print(prefix); pw.print("  supportsScreens=[");
             boolean first = true;
-            if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS) != 0) {
+            if ((pkg.getFlags() & ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS) != 0) {
                 if (!first)
                     pw.print(", ");
                 first = false;
                 pw.print("small");
             }
-            if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS) != 0) {
+            if ((pkg.getFlags() & ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS) != 0) {
                 if (!first)
                     pw.print(", ");
                 first = false;
                 pw.print("medium");
             }
-            if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) != 0) {
+            if ((pkg.getFlags() & ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) != 0) {
                 if (!first)
                     pw.print(", ");
                 first = false;
                 pw.print("large");
             }
-            if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS) != 0) {
+            if ((pkg.getFlags() & ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS) != 0) {
                 if (!first)
                     pw.print(", ");
                 first = false;
                 pw.print("xlarge");
             }
-            if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS) != 0) {
+            if ((pkg.getFlags() & ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS) != 0) {
                 if (!first)
                     pw.print(", ");
                 first = false;
                 pw.print("resizeable");
             }
-            if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES) != 0) {
+            if ((pkg.getFlags() & ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES) != 0) {
                 if (!first)
                     pw.print(", ");
                 first = false;
                 pw.print("anyDensity");
             }
             pw.println("]");
-            if (ps.pkg.libraryNames != null && ps.pkg.libraryNames.size() > 0) {
+            List<String> libraryNames = pkg.getLibraryNames();
+            if (libraryNames != null && libraryNames.size() > 0) {
                 pw.print(prefix); pw.println("  dynamic libraries:");
-                for (int i = 0; i<ps.pkg.libraryNames.size(); i++) {
+                for (int i = 0; i< libraryNames.size(); i++) {
                     pw.print(prefix); pw.print("    ");
-                            pw.println(ps.pkg.libraryNames.get(i));
+                            pw.println(libraryNames.get(i));
                 }
             }
-            if (ps.pkg.staticSharedLibName != null) {
+            if (pkg.getStaticSharedLibName() != null) {
                 pw.print(prefix); pw.println("  static library:");
                 pw.print(prefix); pw.print("    ");
-                pw.print("name:"); pw.print(ps.pkg.staticSharedLibName);
-                pw.print(" version:"); pw.println(ps.pkg.staticSharedLibVersion);
+                pw.print("name:"); pw.print(pkg.getStaticSharedLibName());
+                pw.print(" version:"); pw.println(pkg.getStaticSharedLibVersion());
             }
-            if (ps.pkg.usesLibraries != null && ps.pkg.usesLibraries.size() > 0) {
+
+            List<String> usesLibraries = pkg.getUsesLibraries();
+            if (usesLibraries != null && usesLibraries.size() > 0) {
                 pw.print(prefix); pw.println("  usesLibraries:");
-                for (int i=0; i<ps.pkg.usesLibraries.size(); i++) {
-                    pw.print(prefix); pw.print("    "); pw.println(ps.pkg.usesLibraries.get(i));
+                for (int i=0; i< usesLibraries.size(); i++) {
+                    pw.print(prefix); pw.print("    "); pw.println(usesLibraries.get(i));
                 }
             }
-            if (ps.pkg.usesStaticLibraries != null
-                    && ps.pkg.usesStaticLibraries.size() > 0) {
+
+            List<String> usesStaticLibraries = pkg.getUsesStaticLibraries();
+            long[] usesStaticLibrariesVersions = pkg.getUsesStaticLibrariesVersions();
+            if (usesStaticLibraries != null
+                    && usesStaticLibraries.size() > 0) {
                 pw.print(prefix); pw.println("  usesStaticLibraries:");
-                for (int i=0; i<ps.pkg.usesStaticLibraries.size(); i++) {
+                for (int i=0; i< usesStaticLibraries.size(); i++) {
                     pw.print(prefix); pw.print("    ");
-                    pw.print(ps.pkg.usesStaticLibraries.get(i)); pw.print(" version:");
-                            pw.println(ps.pkg.usesStaticLibrariesVersions[i]);
+                    pw.print(usesStaticLibraries.get(i)); pw.print(" version:");
+                            pw.println(usesStaticLibrariesVersions[i]);
                 }
             }
-            if (ps.pkg.usesOptionalLibraries != null
-                    && ps.pkg.usesOptionalLibraries.size() > 0) {
+
+            List<String> usesOptionalLibraries = pkg.getUsesOptionalLibraries();
+            if (usesOptionalLibraries != null
+                    && usesOptionalLibraries.size() > 0) {
                 pw.print(prefix); pw.println("  usesOptionalLibraries:");
-                for (int i=0; i<ps.pkg.usesOptionalLibraries.size(); i++) {
+                for (int i=0; i< usesOptionalLibraries.size(); i++) {
                     pw.print(prefix); pw.print("    ");
-                    pw.println(ps.pkg.usesOptionalLibraries.get(i));
+                    pw.println(usesOptionalLibraries.get(i));
                 }
             }
-            if (ps.pkg.usesLibraryFiles != null
-                    && ps.pkg.usesLibraryFiles.length > 0) {
+
+            String[] usesLibraryFiles = pkg.getUsesLibraryFiles();
+            if (usesLibraryFiles != null
+                    && usesLibraryFiles.length > 0) {
                 pw.print(prefix); pw.println("  usesLibraryFiles:");
-                for (int i=0; i<ps.pkg.usesLibraryFiles.length; i++) {
-                    pw.print(prefix); pw.print("    "); pw.println(ps.pkg.usesLibraryFiles[i]);
+                for (int i=0; i< usesLibraryFiles.length; i++) {
+                    pw.print(prefix); pw.print("    "); pw.println(usesLibraryFiles[i]);
                 }
             }
         }
@@ -4709,40 +4605,40 @@
         pw.print(prefix); pw.print("  pkgFlags="); printFlags(pw, ps.pkgFlags, FLAG_DUMP_SPEC);
                 pw.println();
 
-        if (ps.pkg != null && ps.pkg.mOverlayTarget != null) {
-            pw.print(prefix); pw.print("  overlayTarget="); pw.println(ps.pkg.mOverlayTarget);
-            pw.print(prefix); pw.print("  overlayCategory="); pw.println(ps.pkg.mOverlayCategory);
+        if (pkg != null && pkg.getOverlayTarget() != null) {
+            pw.print(prefix); pw.print("  overlayTarget="); pw.println(pkg.getOverlayTarget());
+            pw.print(prefix); pw.print("  overlayCategory="); pw.println(pkg.getOverlayCategory());
         }
 
-        if (ps.pkg != null && ps.pkg.permissions != null && ps.pkg.permissions.size() > 0) {
-            final ArrayList<PackageParser.Permission> perms = ps.pkg.permissions;
+        if (pkg != null && pkg.getPermissions() != null && pkg.getPermissions().size() > 0) {
+            final List<ParsedPermission> perms = pkg.getPermissions();
             pw.print(prefix); pw.println("  declared permissions:");
             for (int i=0; i<perms.size(); i++) {
-                PackageParser.Permission perm = perms.get(i);
+                ParsedPermission perm = perms.get(i);
                 if (permissionNames != null
-                        && !permissionNames.contains(perm.info.name)) {
+                        && !permissionNames.contains(perm.getName())) {
                     continue;
                 }
-                pw.print(prefix); pw.print("    "); pw.print(perm.info.name);
+                pw.print(prefix); pw.print("    "); pw.print(perm.getName());
                 pw.print(": prot=");
-                pw.print(PermissionInfo.protectionToString(perm.info.protectionLevel));
-                if ((perm.info.flags&PermissionInfo.FLAG_COSTS_MONEY) != 0) {
+                pw.print(PermissionInfo.protectionToString(perm.protectionLevel));
+                if ((perm.flags&PermissionInfo.FLAG_COSTS_MONEY) != 0) {
                     pw.print(", COSTS_MONEY");
                 }
-                if ((perm.info.flags&PermissionInfo.FLAG_REMOVED) != 0) {
+                if ((perm.flags&PermissionInfo.FLAG_REMOVED) != 0) {
                     pw.print(", HIDDEN");
                 }
-                if ((perm.info.flags&PermissionInfo.FLAG_INSTALLED) != 0) {
+                if ((perm.flags&PermissionInfo.FLAG_INSTALLED) != 0) {
                     pw.print(", INSTALLED");
                 }
                 pw.println();
             }
         }
 
-        if ((permissionNames != null || dumpAll) && ps.pkg != null
-                && ps.pkg.requestedPermissions != null
-                && ps.pkg.requestedPermissions.size() > 0) {
-            final ArrayList<String> perms = ps.pkg.requestedPermissions;
+        if ((permissionNames != null || dumpAll) && pkg != null
+                && pkg.getRequestedPermissions() != null
+                && pkg.getRequestedPermissions().size() > 0) {
+            final List<String> perms = pkg.getRequestedPermissions();
             pw.print(prefix); pw.println("  requested permissions:");
             for (int i=0; i<perms.size(); i++) {
                 String perm = perms.get(i);
@@ -5019,22 +4915,24 @@
         pw.print(mReadMessages.toString());
     }
 
-    private static void dumpSplitNames(PrintWriter pw, PackageParser.Package pkg) {
+    private static void dumpSplitNames(PrintWriter pw, AndroidPackage pkg) {
         if (pkg == null) {
             pw.print("unknown");
         } else {
             // [base:10, config.mdpi, config.xhdpi:12]
             pw.print("[");
             pw.print("base");
-            if (pkg.baseRevisionCode != 0) {
-                pw.print(":"); pw.print(pkg.baseRevisionCode);
+            if (pkg.getBaseRevisionCode() != 0) {
+                pw.print(":"); pw.print(pkg.getBaseRevisionCode());
             }
-            if (pkg.splitNames != null) {
-                for (int i = 0; i < pkg.splitNames.length; i++) {
+            String[] splitNames = pkg.getSplitNames();
+            int[] splitRevisionCodes = pkg.getSplitRevisionCodes();
+            if (splitNames != null) {
+                for (int i = 0; i < splitNames.length; i++) {
                     pw.print(", ");
-                    pw.print(pkg.splitNames[i]);
-                    if (pkg.splitRevisionCodes[i] != 0) {
-                        pw.print(":"); pw.print(pkg.splitRevisionCodes[i]);
+                    pw.print(splitNames[i]);
+                    if (splitRevisionCodes[i] != 0) {
+                        pw.print(":"); pw.print(splitRevisionCodes[i]);
                     }
                 }
             }
@@ -5110,22 +5008,23 @@
     }
 
     void dumpComponents(PrintWriter pw, String prefix, PackageSetting ps) {
-        dumpComponents(pw, prefix, ps, "activities:", ps.pkg.activities);
-        dumpComponents(pw, prefix, ps, "services:", ps.pkg.services);
-        dumpComponents(pw, prefix, ps, "receivers:", ps.pkg.receivers);
-        dumpComponents(pw, prefix, ps, "providers:", ps.pkg.providers);
-        dumpComponents(pw, prefix, ps, "instrumentations:", ps.pkg.instrumentation);
+        // TODO(b/135203078): ParsedComponent toString methods for dumping
+        dumpComponents(pw, prefix, "activities:", ps.pkg.getActivities());
+        dumpComponents(pw, prefix, "services:", ps.pkg.getServices());
+        dumpComponents(pw, prefix, "receivers:", ps.pkg.getReceivers());
+        dumpComponents(pw, prefix, "providers:", ps.pkg.getProviders());
+        dumpComponents(pw, prefix, "instrumentations:", ps.pkg.getInstrumentations());
     }
 
-    void dumpComponents(PrintWriter pw, String prefix, PackageSetting ps,
-            String label, List<? extends PackageParser.Component<?>> list) {
+    void dumpComponents(PrintWriter pw, String prefix, String label,
+            List<? extends ParsedComponent> list) {
         final int size = CollectionUtils.size(list);
         if (size == 0) {
             return;
         }
         pw.print(prefix);pw.println(label);
         for (int i = 0; i < size; i++) {
-            final PackageParser.Component<?> component = list.get(i);
+            final ParsedComponent component = list.get(i);
             pw.print(prefix);pw.print("  ");
             pw.println(component.getComponentName().flattenToShortString());
         }
diff --git a/services/core/java/com/android/server/pm/SharedUserSetting.java b/services/core/java/com/android/server/pm/SharedUserSetting.java
index 6480518..0a42ccf 100644
--- a/services/core/java/com/android/server/pm/SharedUserSetting.java
+++ b/services/core/java/com/android/server/pm/SharedUserSetting.java
@@ -18,7 +18,7 @@
 
 import android.annotation.Nullable;
 import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageParser;
+import android.content.pm.parsing.AndroidPackage;
 import android.service.pm.PackageServiceDumpProto;
 import android.util.ArraySet;
 import android.util.proto.ProtoOutputStream;
@@ -46,7 +46,7 @@
     // that all apps within the sharedUser run in the same selinux context.
     int seInfoTargetSdkVersion;
 
-    final ArraySet<PackageSetting> packages = new ArraySet<PackageSetting>();
+    final ArraySet<PackageSetting> packages = new ArraySet<>();
 
     final PackageSignatures signatures = new PackageSignatures();
     Boolean signaturesChanged;
@@ -98,7 +98,7 @@
         // If this is the first package added to this shared user, temporarily (until next boot) use
         // its targetSdkVersion when assigning seInfo for the shared user.
         if ((packages.size() == 0) && (packageSetting.pkg != null)) {
-            seInfoTargetSdkVersion = packageSetting.pkg.applicationInfo.targetSdkVersion;
+            seInfoTargetSdkVersion = packageSetting.pkg.getTargetSdkVersion();
         }
         if (packages.add(packageSetting)) {
             setFlags(this.pkgFlags | packageSetting.pkgFlags);
@@ -106,11 +106,11 @@
         }
     }
 
-    public @Nullable List<PackageParser.Package> getPackages() {
+    public @Nullable List<AndroidPackage> getPackages() {
         if (packages == null || packages.size() == 0) {
             return null;
         }
-        final ArrayList<PackageParser.Package> pkgList = new ArrayList<>(packages.size());
+        final ArrayList<AndroidPackage> pkgList = new ArrayList<>(packages.size());
         for (PackageSetting ps : packages) {
             if ((ps == null) || (ps.pkg == null)) {
                 continue;
@@ -131,20 +131,20 @@
      * restrictive selinux domain.
      */
     public void fixSeInfoLocked() {
-        final List<PackageParser.Package> pkgList = getPackages();
+        final List<AndroidPackage> pkgList = getPackages();
         if (pkgList == null || pkgList.size() == 0) {
             return;
         }
 
-        for (PackageParser.Package pkg : pkgList) {
-            if (pkg.applicationInfo.targetSdkVersion < seInfoTargetSdkVersion) {
-                seInfoTargetSdkVersion = pkg.applicationInfo.targetSdkVersion;
+        for (AndroidPackage pkg : pkgList) {
+            if (pkg.getTargetSdkVersion() < seInfoTargetSdkVersion) {
+                seInfoTargetSdkVersion = pkg.getTargetSdkVersion();
             }
         }
-        for (PackageParser.Package pkg : pkgList) {
+        for (AndroidPackage pkg : pkgList) {
             final boolean isPrivileged = isPrivileged() | pkg.isPrivileged();
-            pkg.applicationInfo.seInfo = SELinuxMMAC.getSeInfo(pkg, isPrivileged,
-                seInfoTargetSdkVersion);
+            pkg.mutate().setSeInfo(SELinuxMMAC.getSeInfo(pkg, isPrivileged,
+                    seInfoTargetSdkVersion));
         }
     }
 
diff --git a/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java b/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
index 0a6a435..034c010 100644
--- a/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
+++ b/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
@@ -199,7 +199,7 @@
                 final boolean changed = pmInt.setInstalled(pkg, userId, install);
                 if (changed) {
                     Slog.i(TAG, (install ? "Installed " : "Uninstalled ")
-                            + pkg.packageName + " for user " + userId);
+                            + pkg.getPackageName() + " for user " + userId);
                 }
             });
         }
@@ -220,7 +220,7 @@
 
         // Check whether all whitelisted packages are indeed on the system.
         for (String pkgName : allWhitelistedPackages) {
-            PackageParser.Package pkg = pmInt.getPackage(pkgName);
+            AndroidPackage pkg = pmInt.getPackage(pkgName);
             if (pkg == null) {
                 Slog.w(TAG, pkgName + " is whitelisted but not present.");
             } else if (!pkg.isSystem()) {
@@ -234,8 +234,8 @@
         }
         final boolean doWtf = isEnforceMode(mode);
         pmInt.forEachPackage(pkg -> {
-            if (pkg.isSystem() && !allWhitelistedPackages.contains(pkg.manifestPackageName)) {
-                final String msg = "System package " + pkg.manifestPackageName
+            if (pkg.isSystem() && !allWhitelistedPackages.contains(pkg.getManifestPackageName())) {
+                final String msg = "System package " + pkg.getManifestPackageName()
                         + " is not whitelisted using 'install-in-user-type' in SystemConfig "
                         + "for any user types!";
                 if (doWtf) {
@@ -344,7 +344,7 @@
             if (shouldInstallPackage(pkg, mWhitelistedPackagesForUserTypes,
                     whitelistedPackages, isImplicitWhitelistMode, isSystemUser)) {
                 // Although the whitelist uses manifest names, this function returns packageNames.
-                installPackages.add(pkg.packageName);
+                installPackages.add(pkg.getPackageName());
             }
         });
         return installPackages;
@@ -371,7 +371,7 @@
             @NonNull Set<String> userWhitelist, boolean isImplicitWhitelistMode,
             boolean isSystemUser) {
 
-        final String pkgName = sysPkg.manifestPackageName;
+        final String pkgName = sysPkg.getManifestPackageName();
         boolean install = (isImplicitWhitelistMode && !userTypeWhitelist.containsKey(pkgName))
                 || userWhitelist.contains(pkgName);
 
diff --git a/services/core/java/com/android/server/pm/dex/ArtManagerService.java b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
index cc5aec2..486cfef 100644
--- a/services/core/java/com/android/server/pm/dex/ArtManagerService.java
+++ b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
@@ -25,13 +25,13 @@
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
-import android.content.pm.PackageParser;
 import android.content.pm.dex.ArtManager;
 import android.content.pm.dex.ArtManager.ProfileType;
 import android.content.pm.dex.ArtManagerInternal;
 import android.content.pm.dex.DexMetadataHelper;
 import android.content.pm.dex.ISnapshotRuntimeProfileCallback;
 import android.content.pm.dex.PackageOptimizationInfo;
+import android.content.pm.parsing.AndroidPackage;
 import android.os.Binder;
 import android.os.Build;
 import android.os.Handler;
@@ -390,9 +390,10 @@
      *   - create the current primary profile to save time at app startup time.
      *   - copy the profiles from the associated dex metadata file to the reference profile.
      */
-    public void prepareAppProfiles(PackageParser.Package pkg, @UserIdInt int user,
+    public void prepareAppProfiles(
+            AndroidPackage pkg, @UserIdInt int user,
             boolean updateReferenceProfileContent) {
-        final int appId = UserHandle.getAppId(pkg.applicationInfo.uid);
+        final int appId = UserHandle.getAppId(pkg.getUid());
         if (user < 0) {
             Slog.wtf(TAG, "Invalid user id: " + user);
             return;
@@ -415,23 +416,24 @@
                     dexMetadataPath = dexMetadata == null ? null : dexMetadata.getAbsolutePath();
                 }
                 synchronized (mInstaller) {
-                    boolean result = mInstaller.prepareAppProfile(pkg.packageName, user, appId,
+                    boolean result = mInstaller.prepareAppProfile(pkg.getPackageName(), user, appId,
                             profileName, codePath, dexMetadataPath);
                     if (!result) {
                         Slog.e(TAG, "Failed to prepare profile for " +
-                                pkg.packageName + ":" + codePath);
+                                pkg.getPackageName() + ":" + codePath);
                     }
                 }
             }
         } catch (InstallerException e) {
-            Slog.e(TAG, "Failed to prepare profile for " + pkg.packageName, e);
+            Slog.e(TAG, "Failed to prepare profile for " + pkg.getPackageName(), e);
         }
     }
 
     /**
      * Prepares the app profiles for a set of users. {@see ArtManagerService#prepareAppProfiles}.
      */
-    public void prepareAppProfiles(PackageParser.Package pkg, int[] user,
+    public void prepareAppProfiles(
+            AndroidPackage pkg, int[] user,
             boolean updateReferenceProfileContent) {
         for (int i = 0; i < user.length; i++) {
             prepareAppProfiles(pkg, user[i], updateReferenceProfileContent);
@@ -441,12 +443,12 @@
     /**
      * Clear the profiles for the given package.
      */
-    public void clearAppProfiles(PackageParser.Package pkg) {
+    public void clearAppProfiles(AndroidPackage pkg) {
         try {
             ArrayMap<String, String> packageProfileNames = getPackageProfileNames(pkg);
             for (int i = packageProfileNames.size() - 1; i >= 0; i--) {
                 String profileName = packageProfileNames.valueAt(i);
-                mInstaller.clearAppProfiles(pkg.packageName, profileName);
+                mInstaller.clearAppProfiles(pkg.getPackageName(), profileName);
             }
         } catch (InstallerException e) {
             Slog.w(TAG, String.valueOf(e));
@@ -456,15 +458,15 @@
     /**
      * Dumps the profiles for the given package.
      */
-    public void dumpProfiles(PackageParser.Package pkg) {
-        final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
+    public void dumpProfiles(AndroidPackage pkg) {
+        final int sharedGid = UserHandle.getSharedAppGid(pkg.getUid());
         try {
             ArrayMap<String, String> packageProfileNames = getPackageProfileNames(pkg);
             for (int i = packageProfileNames.size() - 1; i >= 0; i--) {
                 String codePath = packageProfileNames.keyAt(i);
                 String profileName = packageProfileNames.valueAt(i);
                 synchronized (mInstallLock) {
-                    mInstaller.dumpProfiles(sharedGid, pkg.packageName, profileName, codePath);
+                    mInstaller.dumpProfiles(sharedGid, pkg.getPackageName(), profileName, codePath);
                 }
             }
         } catch (InstallerException e) {
@@ -475,14 +477,13 @@
     /**
      * Compile layout resources in a given package.
      */
-    public boolean compileLayouts(PackageParser.Package pkg) {
+    public boolean compileLayouts(AndroidPackage pkg) {
         try {
-            final String packageName = pkg.packageName;
-            final String apkPath = pkg.baseCodePath;
-            final ApplicationInfo appInfo = pkg.applicationInfo;
-            final String outDexFile = appInfo.dataDir + "/code_cache/compiled_view.dex";
-            if (appInfo.isPrivilegedApp() || appInfo.isEmbeddedDexUsed()
-                    || appInfo.isDefaultToDeviceProtectedStorage()) {
+            final String packageName = pkg.getPackageName();
+            final String apkPath = pkg.getBaseCodePath();
+            final String outDexFile = pkg.getDataDir() + "/code_cache/compiled_view.dex";
+            if (pkg.isPrivileged() || pkg.isEmbeddedDexUsed()
+                    || pkg.isDefaultToDeviceProtectedStorage()) {
                 // Privileged apps prefer to load trusted code so they don't use compiled views.
                 // If the app is not privileged but prefers code integrity, also avoid compiling
                 // views.
@@ -496,7 +497,7 @@
             try {
                 synchronized (mInstallLock) {
                     return mInstaller.compileLayouts(apkPath, packageName, outDexFile,
-                            appInfo.uid);
+                            pkg.getUid());
                 }
             } finally {
                 Binder.restoreCallingIdentity(callingId);
@@ -512,15 +513,19 @@
      * Build the profiles names for all the package code paths (excluding resource only paths).
      * Return the map [code path -> profile name].
      */
-    private ArrayMap<String, String> getPackageProfileNames(PackageParser.Package pkg) {
+    private ArrayMap<String, String> getPackageProfileNames(AndroidPackage pkg) {
         ArrayMap<String, String> result = new ArrayMap<>();
-        if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0) {
-            result.put(pkg.baseCodePath, ArtManager.getProfileName(null));
+        if ((pkg.getFlags() & ApplicationInfo.FLAG_HAS_CODE) != 0) {
+            result.put(pkg.getBaseCodePath(), ArtManager.getProfileName(null));
         }
-        if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) {
-            for (int i = 0; i < pkg.splitCodePaths.length; i++) {
-                if ((pkg.splitFlags[i] & ApplicationInfo.FLAG_HAS_CODE) != 0) {
-                    result.put(pkg.splitCodePaths[i], ArtManager.getProfileName(pkg.splitNames[i]));
+
+        String[] splitCodePaths = pkg.getSplitCodePaths();
+        int[] splitFlags = pkg.getSplitFlags();
+        String[] splitNames = pkg.getSplitNames();
+        if (!ArrayUtils.isEmpty(splitCodePaths)) {
+            for (int i = 0; i < splitCodePaths.length; i++) {
+                if ((splitFlags[i] & ApplicationInfo.FLAG_HAS_CODE) != 0) {
+                    result.put(splitCodePaths[i], ArtManager.getProfileName(splitNames[i]));
                 }
             }
         }
diff --git a/services/core/java/com/android/server/pm/dex/DexManager.java b/services/core/java/com/android/server/pm/dex/DexManager.java
index 41dcaa5..29183bb 100644
--- a/services/core/java/com/android/server/pm/dex/DexManager.java
+++ b/services/core/java/com/android/server/pm/dex/DexManager.java
@@ -588,7 +588,7 @@
 
         // We found the package. Now record the usage for all declared ISAs.
         boolean update = false;
-        for (String isa : getAppDexInstructionSets(info)) {
+        for (String isa : getAppDexInstructionSets(info.primaryCpuAbi, info.secondaryCpuAbi)) {
             boolean newUpdate = mPackageDexUsage.record(searchResult.mOwningPackageName,
                     dexPath, userId, isa, isUsedByOtherApps, /*primaryOrSplit*/ false,
                     searchResult.mOwningPackageName,
diff --git a/services/core/java/com/android/server/pm/dex/DexoptUtils.java b/services/core/java/com/android/server/pm/dex/DexoptUtils.java
index 5a473c1..6e6b137 100644
--- a/services/core/java/com/android/server/pm/dex/DexoptUtils.java
+++ b/services/core/java/com/android/server/pm/dex/DexoptUtils.java
@@ -18,10 +18,12 @@
 
 import android.content.pm.ApplicationInfo;
 import android.content.pm.SharedLibraryInfo;
+import android.content.pm.parsing.AndroidPackage;
 import android.util.Slog;
 import android.util.SparseArray;
 
 import com.android.internal.os.ClassLoaderFactory;
+import com.android.internal.util.ArrayUtils;
 
 import java.io.File;
 import java.util.List;
@@ -66,7 +68,7 @@
      * {@link android.app.LoadedApk#makePaths(
      * android.app.ActivityThread, boolean, ApplicationInfo, List, List)}.
      */
-    public static String[] getClassLoaderContexts(ApplicationInfo info,
+    public static String[] getClassLoaderContexts(AndroidPackage pkg,
             List<SharedLibraryInfo> sharedLibraries, boolean[] pathsWithCode) {
         // The base class loader context contains only the shared library.
         String sharedLibrariesContext = "";
@@ -75,8 +77,8 @@
         }
 
         String baseApkContextClassLoader = encodeClassLoader(
-                "", info.classLoaderName, sharedLibrariesContext);
-        if (info.getSplitCodePaths() == null) {
+                "", pkg.getAppInfoClassLoaderName(), sharedLibrariesContext);
+        if (pkg.getSplitCodePaths() == null) {
             // The application has no splits.
             return new String[] {baseApkContextClassLoader};
         }
@@ -84,11 +86,11 @@
         // The application has splits. Compute their class loader contexts.
 
         // First, cache the relative paths of the splits and do some sanity checks
-        String[] splitRelativeCodePaths = getSplitRelativeCodePaths(info);
+        String[] splitRelativeCodePaths = getSplitRelativeCodePaths(pkg);
 
         // The splits have an implicit dependency on the base apk.
         // This means that we have to add the base apk file in addition to the shared libraries.
-        String baseApkName = new File(info.getBaseCodePath()).getName();
+        String baseApkName = new File(pkg.getBaseCodePath()).getName();
         String baseClassPath = baseApkName;
 
         // The result is stored in classLoaderContexts.
@@ -97,7 +99,11 @@
         String[] classLoaderContexts = new String[/*base apk*/ 1 + splitRelativeCodePaths.length];
         classLoaderContexts[0] = pathsWithCode[0] ? baseApkContextClassLoader : null;
 
-        if (!info.requestsIsolatedSplitLoading() || info.splitDependencies == null) {
+        SparseArray<int[]> splitDependencies = pkg.getSplitDependencies();
+
+        if (!pkg.requestsIsolatedSplitLoading()
+                || splitDependencies == null
+                || splitDependencies.size() == 0) {
             // If the app didn't request for the splits to be loaded in isolation or if it does not
             // declare inter-split dependencies, then all the splits will be loaded in the base
             // apk class loader (in the order of their definition).
@@ -105,7 +111,7 @@
             for (int i = 1; i < classLoaderContexts.length; i++) {
                 if (pathsWithCode[i]) {
                     classLoaderContexts[i] = encodeClassLoader(
-                            classpath, info.classLoaderName, sharedLibrariesContext);
+                            classpath, pkg.getAppInfoClassLoaderName(), sharedLibrariesContext);
                 } else {
                     classLoaderContexts[i] = null;
                 }
@@ -132,11 +138,10 @@
             String[] splitClassLoaderEncodingCache = new String[splitRelativeCodePaths.length];
             for (int i = 0; i < splitRelativeCodePaths.length; i++) {
                 splitClassLoaderEncodingCache[i] = encodeClassLoader(splitRelativeCodePaths[i],
-                        info.splitClassLoaderNames[i]);
+                        pkg.getSplitClassLoaderNames()[i]);
             }
             String splitDependencyOnBase = encodeClassLoader(
-                    baseClassPath, info.classLoaderName);
-            SparseArray<int[]> splitDependencies = info.splitDependencies;
+                    baseClassPath, pkg.getClassLoaderName());
 
             // Note that not all splits have dependencies (e.g. configuration splits)
             // The splits without dependencies will have classLoaderContexts[config_split_index]
@@ -154,7 +159,8 @@
             // We also need to add the class loader of the current split which should
             // come first in the context.
             for (int i = 1; i < classLoaderContexts.length; i++) {
-                String splitClassLoader = encodeClassLoader("", info.splitClassLoaderNames[i - 1]);
+                String splitClassLoader = encodeClassLoader("",
+                        pkg.getSplitClassLoaderNames()[i - 1]);
                 if (pathsWithCode[i]) {
                     // If classLoaderContexts[i] is null it means that the split does not have
                     // any dependency. In this case its context equals its declared class loader.
@@ -394,11 +400,11 @@
      * Returns the relative paths of the splits declared by the application {@code info}.
      * Assumes that the application declares a non-null array of splits.
      */
-    private static String[] getSplitRelativeCodePaths(ApplicationInfo info) {
-        String baseCodePath = new File(info.getBaseCodePath()).getParent();
-        String[] splitCodePaths = info.getSplitCodePaths();
-        String[] splitRelativeCodePaths = new String[splitCodePaths.length];
-        for (int i = 0; i < splitCodePaths.length; i++) {
+    private static String[] getSplitRelativeCodePaths(AndroidPackage pkg) {
+        String baseCodePath = new File(pkg.getBaseCodePath()).getParent();
+        String[] splitCodePaths = pkg.getSplitCodePaths();
+        String[] splitRelativeCodePaths = new String[ArrayUtils.size(splitCodePaths)];
+        for (int i = 0; i < splitRelativeCodePaths.length; i++) {
             File pathFile = new File(splitCodePaths[i]);
             splitRelativeCodePaths[i] = pathFile.getName();
             // Sanity check that the base paths of the splits are all the same.
diff --git a/services/core/java/com/android/server/pm/dex/ViewCompiler.java b/services/core/java/com/android/server/pm/dex/ViewCompiler.java
index 8d8e17e..b7443f3 100644
--- a/services/core/java/com/android/server/pm/dex/ViewCompiler.java
+++ b/services/core/java/com/android/server/pm/dex/ViewCompiler.java
@@ -16,10 +16,10 @@
 
 package com.android.server.pm.dex;
 
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageParser;
+import android.content.pm.parsing.AndroidPackage;
 import android.os.Binder;
 import android.util.Log;
+
 import com.android.internal.annotations.GuardedBy;
 import com.android.server.pm.Installer;
 
@@ -33,19 +33,18 @@
         mInstaller = installer;
     }
 
-    public boolean compileLayouts(PackageParser.Package pkg) {
+    public boolean compileLayouts(AndroidPackage pkg) {
         try {
-            final String packageName = pkg.packageName;
-            final String apkPath = pkg.baseCodePath;
-            final ApplicationInfo appInfo = pkg.applicationInfo;
-            final String outDexFile = appInfo.dataDir + "/code_cache/compiled_view.dex";
+            final String packageName = pkg.getPackageName();
+            final String apkPath = pkg.getBaseCodePath();
+            final String outDexFile = pkg.getDataDir() + "/code_cache/compiled_view.dex";
             Log.i("PackageManager", "Compiling layouts in " + packageName + " (" + apkPath +
                 ") to " + outDexFile);
             long callingId = Binder.clearCallingIdentity();
             try {
                 synchronized (mInstallLock) {
                     return mInstaller.compileLayouts(apkPath, packageName, outDexFile,
-                        appInfo.uid);
+                        pkg.getUid());
                 }
             } finally {
                 Binder.restoreCallingIdentity(callingId);
diff --git a/services/core/java/com/android/server/pm/permission/BasePermission.java b/services/core/java/com/android/server/pm/permission/BasePermission.java
index c39dcfe..cc70aa7 100644
--- a/services/core/java/com/android/server/pm/permission/BasePermission.java
+++ b/services/core/java/com/android/server/pm/permission/BasePermission.java
@@ -29,10 +29,12 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.content.pm.PackageParser;
-import android.content.pm.PackageParser.Permission;
+import android.content.pm.PackageManagerInternal;
 import android.content.pm.PermissionInfo;
 import android.content.pm.Signature;
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.ComponentParseUtils.ParsedPermission;
+import android.content.pm.parsing.PackageInfoUtils;
 import android.os.UserHandle;
 import android.util.Log;
 import android.util.Slog;
@@ -89,7 +91,7 @@
 
     int protectionLevel;
 
-    PackageParser.Permission perm;
+    ParsedPermission perm;
 
     PermissionInfo pendingPermissionInfo;
 
@@ -113,12 +115,6 @@
         protectionLevel = PermissionInfo.PROTECTION_SIGNATURE;
     }
 
-    @Override
-    public String toString() {
-        return "BasePermission{" + Integer.toHexString(System.identityHashCode(this)) + " " + name
-                + "}";
-    }
-
     public String getName() {
         return name;
     }
@@ -144,7 +140,7 @@
         this.gids = gids;
         this.perUser = perUser;
     }
-    public void setPermission(@Nullable Permission perm) {
+    public void setPermission(@Nullable ParsedPermission perm) {
         this.perm = perm;
     }
     public void setSourcePackageSetting(PackageSettingBase sourcePackageSetting) {
@@ -165,13 +161,13 @@
 
     public int calculateFootprint(BasePermission perm) {
         if (uid == perm.uid) {
-            return perm.name.length() + perm.perm.info.calculateFootprint();
+            return perm.name.length() + perm.perm.calculateFootprint();
         }
         return 0;
     }
 
-    public boolean isPermission(Permission perm) {
-        return this.perm == perm;
+    public boolean isPermission(ParsedPermission perm) {
+        return Objects.equals(this.perm.className, perm.className);
     }
 
     public boolean isDynamic() {
@@ -189,29 +185,24 @@
     }
 
     public boolean isRemoved() {
-        return perm != null && perm.info != null
-                && (perm.info.flags & PermissionInfo.FLAG_REMOVED) != 0;
+        return perm != null && (perm.flags & PermissionInfo.FLAG_REMOVED) != 0;
     }
 
     public boolean isSoftRestricted() {
-        return perm != null && perm.info != null
-                && (perm.info.flags & PermissionInfo.FLAG_SOFT_RESTRICTED) != 0;
+        return perm != null && (perm.flags & PermissionInfo.FLAG_SOFT_RESTRICTED) != 0;
     }
 
     public boolean isHardRestricted() {
-        return perm != null && perm.info != null
-                && (perm.info.flags & PermissionInfo.FLAG_HARD_RESTRICTED) != 0;
+        return perm != null && (perm.flags & PermissionInfo.FLAG_HARD_RESTRICTED) != 0;
     }
 
     public boolean isHardOrSoftRestricted() {
-        return perm != null && perm.info != null
-                && (perm.info.flags & (PermissionInfo.FLAG_HARD_RESTRICTED
+        return perm != null && (perm.flags & (PermissionInfo.FLAG_HARD_RESTRICTED
                 | PermissionInfo.FLAG_SOFT_RESTRICTED)) != 0;
     }
 
     public boolean isImmutablyRestricted() {
-        return perm != null && perm.info != null
-                && (perm.info.flags & PermissionInfo.FLAG_IMMUTABLY_RESTRICTED) != 0;
+        return perm != null && (perm.flags & PermissionInfo.FLAG_IMMUTABLY_RESTRICTED) != 0;
     }
 
     public boolean isSignature() {
@@ -300,13 +291,12 @@
                 (this.protectionLevel != protectionLevel
                     || perm == null
                     || uid != tree.uid
-                    || !perm.owner.equals(tree.perm.owner)
-                    || !comparePermissionInfos(perm.info, info));
+                    || !Objects.equals(perm.getPackageName(), tree.perm.getPackageName())
+                    || !comparePermissionInfos(perm, info));
         this.protectionLevel = protectionLevel;
         info = new PermissionInfo(info);
         info.protectionLevel = protectionLevel;
-        perm = new PackageParser.Permission(tree.perm.owner, info);
-        perm.info.packageName = tree.perm.info.packageName;
+        perm = new ParsedPermission(tree.perm);
         uid = tree.uid;
         return changed;
     }
@@ -319,71 +309,89 @@
             final BasePermission tree = findPermissionTree(permissionTrees, name);
             if (tree != null && tree.perm != null) {
                 sourcePackageSetting = tree.sourcePackageSetting;
-                perm = new PackageParser.Permission(tree.perm.owner,
-                        new PermissionInfo(pendingPermissionInfo));
-                perm.info.packageName = tree.perm.info.packageName;
-                perm.info.name = name;
+                perm = new ParsedPermission(tree.perm);
+                perm.protectionLevel = pendingPermissionInfo.protectionLevel;
+                perm.flags = pendingPermissionInfo.flags;
+                perm.setGroup(pendingPermissionInfo.group);
+                perm.backgroundPermission = pendingPermissionInfo.backgroundPermission;
+                perm.descriptionRes = pendingPermissionInfo.descriptionRes;
+                perm.requestRes = pendingPermissionInfo.requestRes;
+                perm.setPackageName(tree.perm.getPackageName());
+                perm.setName(name);
                 uid = tree.uid;
             }
         }
     }
 
-    static BasePermission createOrUpdate(@Nullable BasePermission bp, @NonNull Permission p,
-            @NonNull PackageParser.Package pkg, Collection<BasePermission> permissionTrees,
+    static BasePermission createOrUpdate(PackageManagerInternal packageManagerInternal,
+            @Nullable BasePermission bp, @NonNull ParsedPermission p,
+            @NonNull AndroidPackage pkg, Collection<BasePermission> permissionTrees,
             boolean chatty) {
-        final PackageSettingBase pkgSetting = (PackageSettingBase) pkg.mExtras;
+        final PackageSettingBase pkgSetting =
+                (PackageSettingBase) packageManagerInternal.getPackageSetting(pkg.getPackageName());
         // Allow system apps to redefine non-system permissions
-        if (bp != null && !Objects.equals(bp.sourcePackageName, p.info.packageName)) {
-            final boolean currentOwnerIsSystem = (bp.perm != null
-                    && bp.perm.owner.isSystem());
-            if (p.owner.isSystem()) {
+        if (bp != null && !Objects.equals(bp.sourcePackageName, p.getPackageName())) {
+            final boolean currentOwnerIsSystem;
+            if (bp.perm == null) {
+                currentOwnerIsSystem = false;
+            } else {
+                AndroidPackage currentPackage = packageManagerInternal.getPackage(
+                        bp.perm.getPackageName());
+                if (currentPackage == null) {
+                    currentOwnerIsSystem = false;
+                } else {
+                    currentOwnerIsSystem = currentPackage.isSystem();
+                }
+            }
+
+            if (pkg.isSystem()) {
                 if (bp.type == BasePermission.TYPE_BUILTIN && bp.perm == null) {
                     // It's a built-in permission and no owner, take ownership now
+                    p.flags |= PermissionInfo.FLAG_INSTALLED;
                     bp.sourcePackageSetting = pkgSetting;
                     bp.perm = p;
-                    bp.uid = pkg.applicationInfo.uid;
-                    bp.sourcePackageName = p.info.packageName;
-                    p.info.flags |= PermissionInfo.FLAG_INSTALLED;
+                    bp.uid = pkg.getUid();
+                    bp.sourcePackageName = p.getPackageName();
                 } else if (!currentOwnerIsSystem) {
-                    String msg = "New decl " + p.owner + " of permission  "
-                            + p.info.name + " is system; overriding " + bp.sourcePackageName;
+                    String msg = "New decl " + pkg + " of permission  "
+                            + p.getName() + " is system; overriding " + bp.sourcePackageName;
                     PackageManagerService.reportSettingsProblem(Log.WARN, msg);
                     bp = null;
                 }
             }
         }
         if (bp == null) {
-            bp = new BasePermission(p.info.name, p.info.packageName, TYPE_NORMAL);
+            bp = new BasePermission(p.getName(), p.getPackageName(), TYPE_NORMAL);
         }
         StringBuilder r = null;
         if (bp.perm == null) {
             if (bp.sourcePackageName == null
-                    || bp.sourcePackageName.equals(p.info.packageName)) {
-                final BasePermission tree = findPermissionTree(permissionTrees, p.info.name);
+                    || bp.sourcePackageName.equals(p.getPackageName())) {
+                final BasePermission tree = findPermissionTree(permissionTrees, p.getName());
                 if (tree == null
-                        || tree.sourcePackageName.equals(p.info.packageName)) {
+                        || tree.sourcePackageName.equals(p.getPackageName())) {
+                    p.flags |= PermissionInfo.FLAG_INSTALLED;
                     bp.sourcePackageSetting = pkgSetting;
                     bp.perm = p;
-                    bp.uid = pkg.applicationInfo.uid;
-                    bp.sourcePackageName = p.info.packageName;
-                    p.info.flags |= PermissionInfo.FLAG_INSTALLED;
+                    bp.uid = pkg.getUid();
+                    bp.sourcePackageName = p.getPackageName();
                     if (chatty) {
                         if (r == null) {
                             r = new StringBuilder(256);
                         } else {
                             r.append(' ');
                         }
-                        r.append(p.info.name);
+                        r.append(p.getName());
                     }
                 } else {
-                    Slog.w(TAG, "Permission " + p.info.name + " from package "
-                            + p.info.packageName + " ignored: base tree "
+                    Slog.w(TAG, "Permission " + p.getName() + " from package "
+                            + p.getPackageName() + " ignored: base tree "
                             + tree.name + " is from package "
                             + tree.sourcePackageName);
                 }
             } else {
-                Slog.w(TAG, "Permission " + p.info.name + " from package "
-                        + p.info.packageName + " ignored: original from "
+                Slog.w(TAG, "Permission " + p.getName() + " from package "
+                        + p.getPackageName() + " ignored: original from "
                         + bp.sourcePackageName);
             }
         } else if (chatty) {
@@ -393,10 +401,10 @@
                 r.append(' ');
             }
             r.append("DUP:");
-            r.append(p.info.name);
+            r.append(p.getName());
         }
-        if (bp.perm == p) {
-            bp.protectionLevel = p.info.protectionLevel;
+        if (bp.perm != null && Objects.equals(bp.perm.className, p.className)) {
+            bp.protectionLevel = p.protectionLevel;
         }
         if (PackageManagerService.DEBUG_PACKAGE_SCANNING && r != null) {
             Log.d(TAG, "  Permissions: " + r);
@@ -420,17 +428,17 @@
         throw new SecurityException("No permission tree found for " + permName);
     }
 
-    public void enforceDeclaredUsedAndRuntimeOrDevelopment(PackageParser.Package pkg) {
-        final PackageSetting pkgSetting = (PackageSetting) pkg.mExtras;
+    public void enforceDeclaredUsedAndRuntimeOrDevelopment(AndroidPackage pkg,
+            PackageSetting pkgSetting) {
         final PermissionsState permsState = pkgSetting.getPermissionsState();
-        int index = pkg.requestedPermissions.indexOf(name);
+        int index = pkg.getRequestedPermissions().indexOf(name);
         if (!permsState.hasRequestedPermission(name) && index == -1) {
-            throw new SecurityException("Package " + pkg.packageName
+            throw new SecurityException("Package " + pkg.getPackageName()
                     + " has not requested permission " + name);
         }
         if (!isRuntime() && !isDevelopment()) {
-            throw new SecurityException("Permission " + name
-                    + " requested by " + pkg.packageName + " is not a changeable permission type");
+            throw new SecurityException("Permission " + name + " requested by "
+                    + pkg.getPackageName() + " is not a changeable permission type");
         }
     }
 
@@ -448,12 +456,12 @@
 
     public @Nullable PermissionInfo generatePermissionInfo(@NonNull String groupName, int flags) {
         if (groupName == null) {
-            if (perm == null || perm.info.group == null) {
+            if (perm == null || perm.getGroup() == null) {
                 return generatePermissionInfo(protectionLevel, flags);
             }
         } else {
-            if (perm != null && groupName.equals(perm.info.group)) {
-                return PackageParser.generatePermissionInfo(perm, flags);
+            if (perm != null && groupName.equals(perm.getGroup())) {
+                return PackageInfoUtils.generatePermissionInfo(perm, flags);
             }
         }
         return null;
@@ -463,8 +471,8 @@
         PermissionInfo permissionInfo;
         if (perm != null) {
             final boolean protectionLevelChanged = protectionLevel != adjustedProtectionLevel;
-            permissionInfo = PackageParser.generatePermissionInfo(perm, flags);
-            if (protectionLevelChanged && permissionInfo == perm.info) {
+            permissionInfo = PackageInfoUtils.generatePermissionInfo(perm, flags);
+            if (protectionLevelChanged) {
                 // if we return different protection level, don't use the cached info
                 permissionInfo = new PermissionInfo(permissionInfo);
                 permissionInfo.protectionLevel = adjustedProtectionLevel;
@@ -544,14 +552,18 @@
             serializer.attribute(null, "protection", Integer.toString(protectionLevel));
         }
         if (type == BasePermission.TYPE_DYNAMIC) {
-            final PermissionInfo pi = perm != null ? perm.info : pendingPermissionInfo;
-            if (pi != null) {
+            if (perm != null || pendingPermissionInfo != null) {
                 serializer.attribute(null, "type", "dynamic");
-                if (pi.icon != 0) {
-                    serializer.attribute(null, "icon", Integer.toString(pi.icon));
+                int icon = perm != null ? perm.icon : pendingPermissionInfo.icon;
+                CharSequence nonLocalizedLabel = perm != null
+                        ? perm.nonLocalizedLabel
+                        : pendingPermissionInfo.nonLocalizedLabel;
+
+                if (icon != 0) {
+                    serializer.attribute(null, "icon", Integer.toString(icon));
                 }
-                if (pi.nonLocalizedLabel != null) {
-                    serializer.attribute(null, "label", pi.nonLocalizedLabel.toString());
+                if (nonLocalizedLabel != null) {
+                    serializer.attribute(null, "label", nonLocalizedLabel.toString());
                 }
             }
         }
@@ -571,14 +583,14 @@
         return s1.equals(s2);
     }
 
-    private static boolean comparePermissionInfos(PermissionInfo pi1, PermissionInfo pi2) {
+    private static boolean comparePermissionInfos(ParsedPermission pi1, PermissionInfo pi2) {
         if (pi1.icon != pi2.icon) return false;
         if (pi1.logo != pi2.logo) return false;
         if (pi1.protectionLevel != pi2.protectionLevel) return false;
-        if (!compareStrings(pi1.name, pi2.name)) return false;
+        if (!compareStrings(pi1.getName(), pi2.name)) return false;
         if (!compareStrings(pi1.nonLocalizedLabel, pi2.nonLocalizedLabel)) return false;
         // We'll take care of setting this one.
-        if (!compareStrings(pi1.packageName, pi2.packageName)) return false;
+        if (!compareStrings(pi1.getPackageName(), pi2.packageName)) return false;
         // These are not currently stored in settings.
         //if (!compareStrings(pi1.group, pi2.group)) return false;
         //if (!compareStrings(pi1.nonLocalizedDescription, pi2.nonLocalizedDescription)) return false;
@@ -614,9 +626,9 @@
                 pw.println(PermissionInfo.protectionToString(protectionLevel));
         if (perm != null) {
             pw.print("    perm="); pw.println(perm);
-            if ((perm.info.flags & PermissionInfo.FLAG_INSTALLED) == 0
-                    || (perm.info.flags & PermissionInfo.FLAG_REMOVED) != 0) {
-                pw.print("    flags=0x"); pw.println(Integer.toHexString(perm.info.flags));
+            if ((perm.flags & PermissionInfo.FLAG_INSTALLED) == 0
+                    || (perm.flags & PermissionInfo.FLAG_REMOVED) != 0) {
+                pw.print("    flags=0x"); pw.println(Integer.toHexString(perm.flags));
             }
         }
         if (sourcePackageSetting != null) {
@@ -628,4 +640,20 @@
         }
         return true;
     }
+
+    @Override
+    public String toString() {
+        return "BasePermission{" +
+                "name='" + name + '\'' +
+                ", type=" + type +
+                ", sourcePackageName='" + sourcePackageName + '\'' +
+                ", sourcePackageSetting=" + sourcePackageSetting +
+                ", protectionLevel=" + protectionLevel +
+                ", perm=" + perm +
+                ", pendingPermissionInfo=" + pendingPermissionInfo +
+                ", uid=" + uid +
+                ", gids=" + Arrays.toString(gids) +
+                ", perUser=" + perUser +
+                '}';
+    }
 }
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 2ffba45..369e7bb 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -63,10 +63,13 @@
 import android.content.pm.PackageManager.PermissionWhitelistFlags;
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.PackageParser;
-import android.content.pm.PackageParser.Package;
 import android.content.pm.ParceledListSlice;
 import android.content.pm.PermissionGroupInfo;
 import android.content.pm.PermissionInfo;
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.ComponentParseUtils.ParsedPermission;
+import android.content.pm.parsing.ComponentParseUtils.ParsedPermissionGroup;
+import android.content.pm.parsing.PackageInfoUtils;
 import android.content.pm.permission.SplitPermissionInfoParcelable;
 import android.metrics.LogMaker;
 import android.os.Binder;
@@ -419,7 +422,8 @@
         }
     }
 
-    @Nullable BasePermission getPermission(String permName) {
+    @Nullable
+    BasePermission getPermission(String permName) {
         synchronized (mLock) {
             return mSettings.getPermissionLocked(permName);
         }
@@ -453,10 +457,9 @@
         }
         synchronized (mLock) {
             final int n = mSettings.mPermissionGroups.size();
-            final ArrayList<PermissionGroupInfo> out =
-                    new ArrayList<PermissionGroupInfo>(n);
-            for (PackageParser.PermissionGroup pg : mSettings.mPermissionGroups.values()) {
-                out.add(PackageParser.generatePermissionGroupInfo(pg, flags));
+            final ArrayList<PermissionGroupInfo> out = new ArrayList<>(n);
+            for (ParsedPermissionGroup pg : mSettings.mPermissionGroups.values()) {
+                out.add(PackageInfoUtils.generatePermissionGroupInfo(pg, flags));
             }
             return new ParceledListSlice<>(out);
         }
@@ -472,7 +475,7 @@
             return null;
         }
         synchronized (mLock) {
-            return PackageParser.generatePermissionGroupInfo(
+            return PackageInfoUtils.generatePermissionGroupInfo(
                     mSettings.mPermissionGroups.get(groupName), flags);
         }
     }
@@ -596,8 +599,13 @@
                 false, // requirePermissionWhenSameUser
                 "getPermissionFlags");
 
-        final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName);
-        if (pkg == null || pkg.mExtras == null) {
+        final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName);
+        if (pkg == null) {
+            return 0;
+        }
+        final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting(
+                pkg.getPackageName());
+        if (ps == null) {
             return 0;
         }
         synchronized (mLock) {
@@ -608,7 +616,6 @@
         if (mPackageManagerInt.filterAppAccess(pkg, callingUid, userId)) {
             return 0;
         }
-        final PackageSetting ps = (PackageSetting) pkg.mExtras;
         PermissionsState permissionsState = ps.getPermissionsState();
         return permissionsState.getPermissionFlags(permName, userId);
     }
@@ -695,8 +702,10 @@
             flagValues &= ~PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION;
         }
 
-        final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName);
-        if (pkg == null || pkg.mExtras == null) {
+        final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName);
+        final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting(
+                packageName);
+        if (pkg == null || ps == null) {
             Log.e(TAG, "Unknown package: " + packageName);
             return;
         }
@@ -712,7 +721,6 @@
             throw new IllegalArgumentException("Unknown permission: " + permName);
         }
 
-        final PackageSetting ps = (PackageSetting) pkg.mExtras;
         final PermissionsState permissionsState = ps.getPermissionsState();
         final boolean hadState =
                 permissionsState.getRuntimePermissionState(permName, userId) != null;
@@ -725,11 +733,11 @@
             // Install and runtime permissions are stored in different places,
             // so figure out what permission changed and persist the change.
             if (permissionsState.getInstallPermissionState(permName) != null) {
-                callback.onInstallPermissionUpdatedNotifyListener(pkg.applicationInfo.uid);
+                callback.onInstallPermissionUpdatedNotifyListener(pkg.getUid());
             } else if (permissionsState.getRuntimePermissionState(permName, userId) != null
                     || hadState) {
-                callback.onPermissionUpdatedNotifyListener(new int[] { userId }, false,
-                        pkg.applicationInfo.uid);
+                callback.onPermissionUpdatedNotifyListener(new int[]{userId}, false,
+                        pkg.getUid());
             }
         }
     }
@@ -761,18 +769,16 @@
                 ? flagValues : flagValues & ~PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
 
         final boolean[] changed = new boolean[1];
-        mPackageManagerInt.forEachPackage(new Consumer<PackageParser.Package>() {
-            @Override
-            public void accept(Package pkg) {
-                final PackageSetting ps = (PackageSetting) pkg.mExtras;
-                if (ps == null) {
-                    return;
-                }
-                final PermissionsState permissionsState = ps.getPermissionsState();
-                changed[0] |= permissionsState.updatePermissionFlagsForAllPermissions(
-                        userId, effectiveFlagMask, effectiveFlagValues);
-                mOnPermissionChangeListeners.onPermissionsChanged(pkg.applicationInfo.uid);
+        mPackageManagerInt.forEachPackage(pkg -> {
+            final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting(
+                    pkg.getPackageName());
+            if (ps == null) {
+                return;
             }
+            final PermissionsState permissionsState = ps.getPermissionsState();
+            changed[0] |= permissionsState.updatePermissionFlagsForAllPermissions(
+                    userId, effectiveFlagMask, effectiveFlagValues);
+            mOnPermissionChangeListeners.onPermissionsChanged(pkg.getUid());
         });
 
         if (changed[0]) {
@@ -812,7 +818,7 @@
     private int checkPermissionInternal(@NonNull Package pkg, boolean isPackageExplicit,
             @NonNull String permissionName, @UserIdInt int userId) {
         final int callingUid = getCallingUid();
-        if (isPackageExplicit || pkg.mSharedUserId == null) {
+        if (isPackageExplicit || pkg.getSharedUserId() == null) {
             if (mPackageManagerInt.filterAppAccess(pkg, callingUid, userId)) {
                 return PackageManager.PERMISSION_DENIED;
             }
@@ -822,8 +828,9 @@
             }
         }
 
-        final int uid = UserHandle.getUid(userId, pkg.applicationInfo.uid);
-        final PackageSetting ps = (PackageSetting) pkg.mExtras;
+        final int uid = UserHandle.getUid(userId, pkg.getUid());
+        final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting(
+                pkg.getPackageName());
         if (ps == null) {
             return PackageManager.PERMISSION_DENIED;
         }
@@ -953,7 +960,7 @@
                     "getWhitelistedRestrictedPermissions for user " + userId);
         }
 
-        final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName);
+        final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName);
         if (pkg == null) {
             return null;
         }
@@ -986,7 +993,7 @@
         final long identity = Binder.clearCallingIdentity();
         try {
             final PermissionsState permissionsState =
-                    PackageManagerServiceUtils.getPermissionsState(pkg);
+                    PackageManagerServiceUtils.getPermissionsState(mPackageManagerInt, pkg);
             if (permissionsState == null) {
                 return null;
             }
@@ -1004,9 +1011,9 @@
 
             ArrayList<String> whitelistedPermissions = null;
 
-            final int permissionCount = pkg.requestedPermissions.size();
+            final int permissionCount = ArrayUtils.size(pkg.getRequestedPermissions());
             for (int i = 0; i < permissionCount; i++) {
-                final String permissionName = pkg.requestedPermissions.get(i);
+                final String permissionName = pkg.getRequestedPermissions().get(i);
                 final int currentFlags =
                         permissionsState.getPermissionFlags(permissionName, userId);
                 if ((currentFlags & queryFlags) != 0) {
@@ -1103,7 +1110,7 @@
                     "setWhitelistedRestrictedPermissions for user " + userId);
         }
 
-        final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName);
+        final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName);
         if (pkg == null) {
             return false;
         }
@@ -1132,7 +1139,7 @@
                         + Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS);
             }
             final List<String> whitelistedPermissions =
-                    getWhitelistedRestrictedPermissions(pkg.packageName, flags, userId);
+                    getWhitelistedRestrictedPermissions(pkg.getPackageName(), flags, userId);
             if (permissions == null || permissions.isEmpty()) {
                 if (whitelistedPermissions == null || whitelistedPermissions.isEmpty()) {
                     return true;
@@ -1206,8 +1213,10 @@
                 false, // requirePermissionWhenSameUser
                 "grantRuntimePermission");
 
-        final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName);
-        if (pkg == null || pkg.mExtras == null) {
+        final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName);
+        final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting(
+                packageName);
+        if (pkg == null || ps == null) {
             Log.e(TAG, "Unknown package: " + packageName);
             return;
         }
@@ -1222,21 +1231,19 @@
             throw new IllegalArgumentException("Unknown package: " + packageName);
         }
 
-        bp.enforceDeclaredUsedAndRuntimeOrDevelopment(pkg);
+        bp.enforceDeclaredUsedAndRuntimeOrDevelopment(pkg, ps);
 
         // If a permission review is required for legacy apps we represent
         // their permissions as always granted runtime ones since we need
         // to keep the review required permission flag per user while an
         // install permission's state is shared across all users.
-        if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M
+        if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.M
                 && bp.isRuntime()) {
             return;
         }
 
-        final int uid = UserHandle.getUid(userId,
-                UserHandle.getAppId(pkg.applicationInfo.uid));
+        final int uid = UserHandle.getUid(userId, UserHandle.getAppId(pkg.getUid()));
 
-        final PackageSetting ps = (PackageSetting) pkg.mExtras;
         final PermissionsState permissionsState = ps.getPermissionsState();
 
         final int flags = permissionsState.getPermissionFlags(permName, userId);
@@ -1259,7 +1266,7 @@
         }
 
         if (bp.isSoftRestricted() && !SoftRestrictedPermissionPolicy.forPermission(mContext,
-                pkg.applicationInfo, UserHandle.of(userId), permName).mayGrantPermission()) {
+                pkg.toAppInfo(), UserHandle.of(userId), permName).mayGrantPermission()) {
             Log.e(TAG, "Cannot grant soft restricted permission " + permName + " for package "
                     + packageName);
             return;
@@ -1282,7 +1289,7 @@
                     + permName + " for package " + packageName);
         }
 
-        if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) {
+        if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.M) {
             Slog.w(TAG, "Cannot grant runtime permission to a legacy app");
             return;
         }
@@ -1295,7 +1302,7 @@
 
             case PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED: {
                 if (callback != null) {
-                    callback.onGidsChanged(UserHandle.getAppId(pkg.applicationInfo.uid), userId);
+                    callback.onGidsChanged(UserHandle.getAppId(pkg.getUid()), userId);
                 }
             }
             break;
@@ -1368,8 +1375,10 @@
                 false, // requirePermissionWhenSameUser
                 "revokeRuntimePermission");
 
-        final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName);
-        if (pkg == null || pkg.mExtras == null) {
+        final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName);
+        final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting(
+                packageName);
+        if (pkg == null || ps == null) {
             Log.e(TAG, "Unknown package: " + packageName);
             return;
         }
@@ -1381,18 +1390,17 @@
             throw new IllegalArgumentException("Unknown permission: " + permName);
         }
 
-        bp.enforceDeclaredUsedAndRuntimeOrDevelopment(pkg);
+        bp.enforceDeclaredUsedAndRuntimeOrDevelopment(pkg, ps);
 
         // If a permission review is required for legacy apps we represent
         // their permissions as always granted runtime ones since we need
         // to keep the review required permission flag per user while an
         // install permission's state is shared across all users.
-        if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M
+        if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.M
                 && bp.isRuntime()) {
             return;
         }
 
-        final PackageSetting ps = (PackageSetting) pkg.mExtras;
         final PermissionsState permissionsState = ps.getPermissionsState();
 
         final int flags = permissionsState.getPermissionFlags(permName, userId);
@@ -1435,7 +1443,7 @@
 
         if (callback != null) {
             callback.onPermissionRevoked(UserHandle.getUid(userId,
-                    UserHandle.getAppId(pkg.applicationInfo.uid)), userId);
+                    UserHandle.getAppId(pkg.getUid())), userId);
         }
 
         if (bp.isRuntime()) {
@@ -1460,7 +1468,7 @@
                 StorageManager.UUID_PRIVATE_INTERNAL, false, mDefaultPermissionCallback);
         for (final int userId : UserManagerService.getInstance().getUserIds()) {
             mPackageManagerInt.forEachPackage(
-                    (PackageParser.Package pkg) -> resetRuntimePermissionsInternal(pkg, userId));
+                    (AndroidPackage pkg) -> resetRuntimePermissionsInternal(pkg, userId));
         }
     }
 
@@ -1471,9 +1479,9 @@
      * @param userId The device user for which to do a reset.
      */
     @GuardedBy("mLock")
-    private void resetRuntimePermissionsInternal(final PackageParser.Package pkg,
+    private void resetRuntimePermissionsInternal(final AndroidPackage pkg,
             final int userId) {
-        final String packageName = pkg.packageName;
+        final String packageName = pkg.getPackageName();
 
         // These are flags that can change base on user actions.
         final int userSettableMask = FLAG_PERMISSION_USER_SET
@@ -1485,7 +1493,7 @@
                 | FLAG_PERMISSION_POLICY_FIXED;
 
         // Delay and combine non-async permission callbacks
-        final int permissionCount = pkg.requestedPermissions.size();
+        final int permissionCount = ArrayUtils.size(pkg.getRequestedPermissions());
         final boolean[] permissionRemoved = new boolean[1];
         final ArraySet<Long> revokedPermissions = new ArraySet<>();
         final IntArray syncUpdatedUsers = new IntArray(permissionCount);
@@ -1552,7 +1560,7 @@
         };
 
         for (int i = 0; i < permissionCount; i++) {
-            final String permName = pkg.requestedPermissions.get(i);
+            final String permName = pkg.getRequestedPermissions().get(i);
             final BasePermission bp;
             synchronized (mLock) {
                 bp = mSettings.getPermissionLocked(permName);
@@ -1567,7 +1575,7 @@
 
             // If shared user we just reset the state to which only this app contributed.
             final String sharedUserId =
-                    mPackageManagerInt.getSharedUserIdForPackage(pkg.packageName);
+                    mPackageManagerInt.getSharedUserIdForPackage(pkg.getPackageName());
             final String[] pkgNames =
                     mPackageManagerInt.getPackagesForSharedUserId(sharedUserId, userId);
             if (pkgNames != null && pkgNames.length > 0) {
@@ -1575,10 +1583,10 @@
                 final int packageCount = pkgNames.length;
                 for (int j = 0; j < packageCount; j++) {
                     final String sharedPkgName = pkgNames[j];
-                    final PackageParser.Package sharedPkg =
+                    final AndroidPackage sharedPkg =
                             mPackageManagerInt.getPackage(sharedPkgName);
-                    if (sharedPkg != null && !sharedPkg.packageName.equals(packageName)
-                            && sharedPkg.requestedPermissions.contains(permName)) {
+                    if (sharedPkg != null && !sharedPkg.getPackageName().equals(packageName)
+                            && sharedPkg.getRequestedPermissions().contains(permName)) {
                         used = true;
                         break;
                     }
@@ -1999,15 +2007,16 @@
             return protectionLevel;
         }
         // Normalize package name to handle renamed packages and static libs
-        final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName);
+        final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName);
         if (pkg == null) {
             return protectionLevel;
         }
-        if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.O) {
+        if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.O) {
             return protectionLevelMasked;
         }
         // Apps that target O see flags for all protection levels.
-        final PackageSetting ps = (PackageSetting) pkg.mExtras;
+        final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting(
+                pkg.getPackageName());
         if (ps == null) {
             return protectionLevel;
         }
@@ -2028,35 +2037,35 @@
      * @param permissionCallback Callback for permission changed
      */
     private void revokeRuntimePermissionsIfGroupChanged(
-            @NonNull PackageParser.Package newPackage,
-            @NonNull PackageParser.Package oldPackage,
+            @NonNull AndroidPackage newPackage,
+            @NonNull AndroidPackage oldPackage,
             @NonNull ArrayList<String> allPackageNames,
             @NonNull PermissionCallback permissionCallback) {
-        final int numOldPackagePermissions = oldPackage.permissions.size();
+        final int numOldPackagePermissions = ArrayUtils.size(oldPackage.getPermissions());
         final ArrayMap<String, String> oldPermissionNameToGroupName
                 = new ArrayMap<>(numOldPackagePermissions);
 
         for (int i = 0; i < numOldPackagePermissions; i++) {
-            final PackageParser.Permission permission = oldPackage.permissions.get(i);
+            final ParsedPermission permission = oldPackage.getPermissions().get(i);
 
-            if (permission.group != null) {
-                oldPermissionNameToGroupName.put(permission.info.name,
-                        permission.group.info.name);
+            if (permission.parsedPermissionGroup != null) {
+                oldPermissionNameToGroupName.put(permission.getName(),
+                        permission.parsedPermissionGroup.getName());
             }
         }
 
         final int callingUid = Binder.getCallingUid();
-        final int numNewPackagePermissions = newPackage.permissions.size();
+        final int numNewPackagePermissions = ArrayUtils.size(newPackage.getPermissions());
         for (int newPermissionNum = 0; newPermissionNum < numNewPackagePermissions;
                 newPermissionNum++) {
-            final PackageParser.Permission newPermission =
-                    newPackage.permissions.get(newPermissionNum);
-            final int newProtection = newPermission.info.getProtection();
+            final ParsedPermission newPermission =
+                    newPackage.getPermissions().get(newPermissionNum);
+            final int newProtection = newPermission.getProtection();
 
             if ((newProtection & PermissionInfo.PROTECTION_DANGEROUS) != 0) {
-                final String permissionName = newPermission.info.name;
-                final String newPermissionGroupName =
-                        newPermission.group == null ? null : newPermission.group.info.name;
+                final String permissionName = newPermission.getName();
+                final String newPermissionGroupName = newPermission.parsedPermissionGroup == null
+                        ? null : newPermission.parsedPermissionGroup.getName();
                 final String oldPermissionGroupName = oldPermissionNameToGroupName.get(
                         permissionName);
 
@@ -2074,7 +2083,7 @@
                                     userId);
                             if (permissionState == PackageManager.PERMISSION_GRANTED) {
                                 EventLog.writeEvent(0x534e4554, "72710897",
-                                        newPackage.applicationInfo.uid,
+                                        newPackage.getUid(),
                                         "Revoking permission " + permissionName +
                                         " from package " + packageName +
                                         " as the group changed from " + oldPermissionGroupName +
@@ -2095,54 +2104,56 @@
         }
     }
 
-    private void addAllPermissions(PackageParser.Package pkg, boolean chatty) {
-        final int N = pkg.permissions.size();
+    private void addAllPermissions(AndroidPackage pkg, boolean chatty) {
+        final int N = ArrayUtils.size(pkg.getPermissions());
         for (int i=0; i<N; i++) {
-            PackageParser.Permission p = pkg.permissions.get(i);
+            ParsedPermission p = pkg.getPermissions().get(i);
 
             // Assume by default that we did not install this permission into the system.
-            p.info.flags &= ~PermissionInfo.FLAG_INSTALLED;
+            p.flags &= ~PermissionInfo.FLAG_INSTALLED;
 
             synchronized (PermissionManagerService.this.mLock) {
                 // Now that permission groups have a special meaning, we ignore permission
                 // groups for legacy apps to prevent unexpected behavior. In particular,
                 // permissions for one app being granted to someone just because they happen
                 // to be in a group defined by another app (before this had no implications).
-                if (pkg.applicationInfo.targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1) {
-                    p.group = mSettings.mPermissionGroups.get(p.info.group);
+                if (pkg.getTargetSdkVersion() > Build.VERSION_CODES.LOLLIPOP_MR1) {
+                    p.parsedPermissionGroup = mSettings.mPermissionGroups.get(p.getGroup());
                     // Warn for a permission in an unknown group.
                     if (DEBUG_PERMISSIONS
-                            && p.info.group != null && p.group == null) {
-                        Slog.i(TAG, "Permission " + p.info.name + " from package "
-                                + p.info.packageName + " in an unknown group " + p.info.group);
+                            && p.getGroup() != null && p.parsedPermissionGroup == null) {
+                        Slog.i(TAG, "Permission " + p.getName() + " from package "
+                                + p.getPackageName() + " in an unknown group " + p.getGroup());
                     }
                 }
 
                 if (p.tree) {
                     final BasePermission bp = BasePermission.createOrUpdate(
-                            mSettings.getPermissionTreeLocked(p.info.name), p, pkg,
+                            mPackageManagerInt,
+                            mSettings.getPermissionTreeLocked(p.getName()), p, pkg,
                             mSettings.getAllPermissionTreesLocked(), chatty);
-                    mSettings.putPermissionTreeLocked(p.info.name, bp);
+                    mSettings.putPermissionTreeLocked(p.getName(), bp);
                 } else {
                     final BasePermission bp = BasePermission.createOrUpdate(
-                            mSettings.getPermissionLocked(p.info.name),
+                            mPackageManagerInt,
+                            mSettings.getPermissionLocked(p.getName()),
                             p, pkg, mSettings.getAllPermissionTreesLocked(), chatty);
-                    mSettings.putPermissionLocked(p.info.name, bp);
+                    mSettings.putPermissionLocked(p.getName(), bp);
                 }
             }
         }
     }
 
-    private void addAllPermissionGroups(PackageParser.Package pkg, boolean chatty) {
-        final int N = pkg.permissionGroups.size();
+    private void addAllPermissionGroups(AndroidPackage pkg, boolean chatty) {
+        final int N = ArrayUtils.size(pkg.getPermissionGroups());
         StringBuilder r = null;
         for (int i=0; i<N; i++) {
-            final PackageParser.PermissionGroup pg = pkg.permissionGroups.get(i);
-            final PackageParser.PermissionGroup cur = mSettings.mPermissionGroups.get(pg.info.name);
-            final String curPackageName = (cur == null) ? null : cur.info.packageName;
-            final boolean isPackageUpdate = pg.info.packageName.equals(curPackageName);
+            final ParsedPermissionGroup pg = pkg.getPermissionGroups().get(i);
+            final ParsedPermissionGroup cur = mSettings.mPermissionGroups.get(pg.getName());
+            final String curPackageName = (cur == null) ? null : cur.getPackageName();
+            final boolean isPackageUpdate = pg.getPackageName().equals(curPackageName);
             if (cur == null || isPackageUpdate) {
-                mSettings.mPermissionGroups.put(pg.info.name, pg);
+                mSettings.mPermissionGroups.put(pg.getName(), pg);
                 if (chatty && DEBUG_PACKAGE_SCANNING) {
                     if (r == null) {
                         r = new StringBuilder(256);
@@ -2152,12 +2163,12 @@
                     if (isPackageUpdate) {
                         r.append("UPD:");
                     }
-                    r.append(pg.info.name);
+                    r.append(pg.getName());
                 }
             } else {
-                Slog.w(TAG, "Permission group " + pg.info.name + " from package "
-                        + pg.info.packageName + " ignored: original from "
-                        + cur.info.packageName);
+                Slog.w(TAG, "Permission group " + pg.getName() + " from package "
+                        + pg.getPackageName() + " ignored: original from "
+                        + cur.getPackageName());
                 if (chatty && DEBUG_PACKAGE_SCANNING) {
                     if (r == null) {
                         r = new StringBuilder(256);
@@ -2165,7 +2176,7 @@
                         r.append(' ');
                     }
                     r.append("DUP:");
-                    r.append(pg.info.name);
+                    r.append(pg.getName());
                 }
             }
         }
@@ -2175,15 +2186,15 @@
 
     }
 
-    private void removeAllPermissions(PackageParser.Package pkg, boolean chatty) {
+    private void removeAllPermissions(AndroidPackage pkg, boolean chatty) {
         synchronized (mLock) {
-            int N = pkg.permissions.size();
+            int N = ArrayUtils.size(pkg.getPermissions());
             StringBuilder r = null;
             for (int i=0; i<N; i++) {
-                PackageParser.Permission p = pkg.permissions.get(i);
-                BasePermission bp = (BasePermission) mSettings.mPermissions.get(p.info.name);
+                ParsedPermission p = pkg.getPermissions().get(i);
+                BasePermission bp = mSettings.mPermissions.get(p.getName());
                 if (bp == null) {
-                    bp = mSettings.mPermissionTrees.get(p.info.name);
+                    bp = mSettings.mPermissionTrees.get(p.getName());
                 }
                 if (bp != null && bp.isPermission(p)) {
                     bp.setPermission(null);
@@ -2193,14 +2204,14 @@
                         } else {
                             r.append(' ');
                         }
-                        r.append(p.info.name);
+                        r.append(p.getName());
                     }
                 }
                 if (p.isAppOp()) {
                     ArraySet<String> appOpPkgs =
-                            mSettings.mAppOpPermissionPackages.get(p.info.name);
+                            mSettings.mAppOpPermissionPackages.get(p.getName());
                     if (appOpPkgs != null) {
-                        appOpPkgs.remove(pkg.packageName);
+                        appOpPkgs.remove(pkg.getPackageName());
                     }
                 }
             }
@@ -2208,14 +2219,14 @@
                 if (DEBUG_REMOVE) Log.d(TAG, "  Permissions: " + r);
             }
 
-            N = pkg.requestedPermissions.size();
+            N = pkg.getRequestedPermissions().size();
             r = null;
             for (int i=0; i<N; i++) {
-                String perm = pkg.requestedPermissions.get(i);
+                String perm = pkg.getRequestedPermissions().get(i);
                 if (mSettings.isPermissionAppOp(perm)) {
                     ArraySet<String> appOpPkgs = mSettings.mAppOpPermissionPackages.get(perm);
                     if (appOpPkgs != null) {
-                        appOpPkgs.remove(pkg.packageName);
+                        appOpPkgs.remove(pkg.getPackageName());
                         if (appOpPkgs.isEmpty()) {
                             mSettings.mAppOpPermissionPackages.remove(perm);
                         }
@@ -2244,7 +2255,7 @@
      * @param packageOfInterest If this is the name of {@code pkg} add extra logging
      * @param callback Result call back
      */
-    private void restorePermissionState(@NonNull PackageParser.Package pkg, boolean replace,
+    private void restorePermissionState(@NonNull AndroidPackage pkg, boolean replace,
             @Nullable String packageOfInterest, @Nullable PermissionCallback callback) {
         // IMPORTANT: There are two types of permissions: install and runtime.
         // Install time permissions are granted when the app is installed to
@@ -2257,7 +2268,8 @@
         // being upgraded to target a newer SDK, in which case dangerous permissions
         // are transformed from install time to runtime ones.
 
-        final PackageSetting ps = (PackageSetting) pkg.mExtras;
+        final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting(
+                pkg.getPackageName());
         if (ps == null) {
             return;
         }
@@ -2298,23 +2310,25 @@
         synchronized (mLock) {
             ArraySet<String> newImplicitPermissions = new ArraySet<>();
 
-            final int N = pkg.requestedPermissions.size();
+            final int N = pkg.getRequestedPermissions().size();
             for (int i = 0; i < N; i++) {
-                final String permName = pkg.requestedPermissions.get(i);
+                final String permName = pkg.getRequestedPermissions().get(i);
                 final BasePermission bp = mSettings.getPermissionLocked(permName);
                 final boolean appSupportsRuntimePermissions =
-                        pkg.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.M;
+                        pkg.getTargetSdkVersion() >= Build.VERSION_CODES.M;
                 String upgradedActivityRecognitionPermission = null;
 
                 if (DEBUG_INSTALL) {
-                    Log.i(TAG, "Package " + pkg.packageName + " checking " + permName + ": " + bp);
+                    Log.i(TAG, "Package " + pkg.getPackageName()
+                            + " checking " + permName + ": " + bp);
                 }
 
                 if (bp == null || bp.getSourcePackageSetting() == null) {
-                    if (packageOfInterest == null || packageOfInterest.equals(pkg.packageName)) {
+                    if (packageOfInterest == null || packageOfInterest.equals(
+                            pkg.getPackageName())) {
                         if (DEBUG_PERMISSIONS) {
                             Slog.i(TAG, "Unknown permission " + permName
-                                    + " in package " + pkg.packageName);
+                                    + " in package " + pkg.getPackageName());
                         }
                     }
                     continue;
@@ -2323,14 +2337,14 @@
                 // Cache newImplicitPermissions before modifing permissionsState as for the shared
                 // uids the original and new state are the same object
                 if (!origPermissions.hasRequestedPermission(permName)
-                        && (pkg.implicitPermissions.contains(permName)
+                        && (pkg.getImplicitPermissions().contains(permName)
                                 || (permName.equals(Manifest.permission.ACTIVITY_RECOGNITION)))) {
-                    if (pkg.implicitPermissions.contains(permName)) {
+                    if (pkg.getImplicitPermissions().contains(permName)) {
                         // If permName is an implicit permission, try to auto-grant
                         newImplicitPermissions.add(permName);
 
                         if (DEBUG_PERMISSIONS) {
-                            Slog.i(TAG, permName + " is newly added for " + pkg.packageName);
+                            Slog.i(TAG, permName + " is newly added for " + pkg.getPackageName());
                         }
                     } else {
                         // Special case for Activity Recognition permission. Even if AR permission
@@ -2353,7 +2367,7 @@
 
                                 if (DEBUG_PERMISSIONS) {
                                     Slog.i(TAG, permName + " is newly added for "
-                                            + pkg.packageName);
+                                            + pkg.getPackageName());
                                 }
                                 break;
                             }
@@ -2362,10 +2376,10 @@
                 }
 
                 // Limit ephemeral apps to ephemeral allowed permissions.
-                if (pkg.applicationInfo.isInstantApp() && !bp.isInstant()) {
+                if (pkg.isInstantApp() && !bp.isInstant()) {
                     if (DEBUG_PERMISSIONS) {
                         Log.i(TAG, "Denying non-ephemeral permission " + bp.getName()
-                                + " for package " + pkg.packageName);
+                                + " for package " + pkg.getPackageName());
                     }
                     continue;
                 }
@@ -2373,7 +2387,7 @@
                 if (bp.isRuntimeOnly() && !appSupportsRuntimePermissions) {
                     if (DEBUG_PERMISSIONS) {
                         Log.i(TAG, "Denying runtime-only permission " + bp.getName()
-                                + " for package " + pkg.packageName);
+                                + " for package " + pkg.getPackageName());
                     }
                     continue;
                 }
@@ -2384,7 +2398,7 @@
 
                 // Keep track of app op permissions.
                 if (bp.isAppOp()) {
-                    mSettings.addAppOpPackage(perm, pkg.packageName);
+                    mSettings.addAppOpPackage(perm, pkg.getPackageName());
                 }
 
                 if (bp.isNormal()) {
@@ -2410,7 +2424,7 @@
 
                 if (DEBUG_PERMISSIONS) {
                     Slog.i(TAG, "Considering granting permission " + perm + " to package "
-                            + pkg.packageName);
+                            + pkg.getPackageName());
                 }
 
                 if (grant != GRANT_DENIED) {
@@ -2696,10 +2710,10 @@
 
                         default: {
                             if (packageOfInterest == null
-                                    || packageOfInterest.equals(pkg.packageName)) {
+                                    || packageOfInterest.equals(pkg.getPackageName())) {
                                 if (DEBUG_PERMISSIONS) {
                                     Slog.i(TAG, "Not granting permission " + perm
-                                            + " to package " + pkg.packageName
+                                            + " to package " + pkg.getPackageName()
                                             + " because it was previously installed without");
                                 }
                             }
@@ -2714,9 +2728,9 @@
                         changedInstallPermission = true;
                         if (DEBUG_PERMISSIONS) {
                             Slog.i(TAG, "Un-granting permission " + perm
-                                    + " from package " + pkg.packageName
+                                    + " from package " + pkg.getPackageName()
                                     + " (protectionLevel=" + bp.getProtectionLevel()
-                                    + " flags=0x" + Integer.toHexString(pkg.applicationInfo.flags)
+                                    + " flags=0x" + Integer.toHexString(pkg.getFlags())
                                     + ")");
                         }
                     } else if (bp.isAppOp()) {
@@ -2724,11 +2738,11 @@
                         // not to be granted, there is a UI for the user to decide.
                         if (DEBUG_PERMISSIONS
                                 && (packageOfInterest == null
-                                        || packageOfInterest.equals(pkg.packageName))) {
+                                        || packageOfInterest.equals(pkg.getPackageName()))) {
                             Slog.i(TAG, "Not granting permission " + perm
-                                    + " to package " + pkg.packageName
+                                    + " to package " + pkg.getPackageName()
                                     + " (protectionLevel=" + bp.getProtectionLevel()
-                                    + " flags=0x" + Integer.toHexString(pkg.applicationInfo.flags)
+                                    + " flags=0x" + Integer.toHexString(pkg.getFlags())
                                     + ")");
                         }
                     }
@@ -2758,7 +2772,7 @@
         }
 
         for (int userId : updatedUserIds) {
-            notifyRuntimePermissionStateChanged(pkg.packageName, userId);
+            notifyRuntimePermissionStateChanged(pkg.getPackageName(), userId);
         }
     }
 
@@ -2774,10 +2788,10 @@
      * @return The updated value of the {@code updatedUserIds} parameter
      */
     private @NonNull int[] revokePermissionsNoLongerImplicitLocked(
-            @NonNull PermissionsState ps, @NonNull PackageParser.Package pkg,
+            @NonNull PermissionsState ps, @NonNull AndroidPackage pkg,
             @NonNull int[] updatedUserIds) {
-        String pkgName = pkg.packageName;
-        boolean supportsRuntimePermissions = pkg.applicationInfo.targetSdkVersion
+        String pkgName = pkg.getPackageName();
+        boolean supportsRuntimePermissions = pkg.getTargetSdkVersion()
                 >= Build.VERSION_CODES.M;
 
         int[] users = UserManagerService.getInstance().getUserIds();
@@ -2786,7 +2800,7 @@
             int userId = users[i];
 
             for (String permission : ps.getPermissions(userId)) {
-                if (!pkg.implicitPermissions.contains(permission)) {
+                if (!pkg.getImplicitPermissions().contains(permission)) {
                     if (!ps.hasInstallPermission(permission)) {
                         int flags = ps.getRuntimePermissionState(permission, userId).getFlags();
 
@@ -2836,9 +2850,9 @@
      */
     private void inheritPermissionStateToNewImplicitPermissionLocked(
             @NonNull ArraySet<String> sourcePerms, @NonNull String newPerm,
-            @NonNull PermissionsState ps, @NonNull PackageParser.Package pkg,
+            @NonNull PermissionsState ps, @NonNull AndroidPackage pkg,
             @UserIdInt int userId) {
-        String pkgName = pkg.packageName;
+        String pkgName = pkg.getPackageName();
         boolean isGranted = false;
         int flags = 0;
 
@@ -2885,10 +2899,10 @@
      * @return The ids of the users that are changed
      */
     private @NonNull int[] checkIfLegacyStorageOpsNeedToBeUpdated(
-            @NonNull PackageParser.Package pkg, boolean replace, @NonNull int[] updatedUserIds) {
-        if (replace && pkg.applicationInfo.hasRequestedLegacyExternalStorage() && (
-                pkg.requestedPermissions.contains(READ_EXTERNAL_STORAGE)
-                        || pkg.requestedPermissions.contains(WRITE_EXTERNAL_STORAGE))) {
+            @NonNull AndroidPackage pkg, boolean replace, @NonNull int[] updatedUserIds) {
+        if (replace && pkg.hasRequestedLegacyExternalStorage() && (
+                pkg.getRequestedPermissions().contains(READ_EXTERNAL_STORAGE)
+                        || pkg.getRequestedPermissions().contains(WRITE_EXTERNAL_STORAGE))) {
             return UserManagerService.getInstance().getUserIds();
         }
 
@@ -2907,10 +2921,10 @@
      */
     private @NonNull int[] setInitialGrantForNewImplicitPermissionsLocked(
             @NonNull PermissionsState origPs,
-            @NonNull PermissionsState ps, @NonNull PackageParser.Package pkg,
+            @NonNull PermissionsState ps, @NonNull AndroidPackage pkg,
             @NonNull ArraySet<String> newImplicitPermissions,
             @NonNull int[] updatedUserIds) {
-        String pkgName = pkg.packageName;
+        String pkgName = pkg.getPackageName();
         ArrayMap<String, ArraySet<String>> newToSplitPerms = new ArrayMap<>();
 
         final List<SplitPermissionInfoParcelable> permissionList = getSplitPermissions();
@@ -2990,17 +3004,17 @@
                 SystemConfig.getInstance().getSplitPermissions());
     }
 
-    private boolean isNewPlatformPermissionForPackage(String perm, PackageParser.Package pkg) {
+    private boolean isNewPlatformPermissionForPackage(String perm, AndroidPackage pkg) {
         boolean allowed = false;
         final int NP = PackageParser.NEW_PERMISSIONS.length;
         for (int ip=0; ip<NP; ip++) {
             final PackageParser.NewPermissionInfo npi
                     = PackageParser.NEW_PERMISSIONS[ip];
             if (npi.name.equals(perm)
-                    && pkg.applicationInfo.targetSdkVersion < npi.sdkVersion) {
+                    && pkg.getTargetSdkVersion() < npi.sdkVersion) {
                 allowed = true;
                 Log.i(TAG, "Auto-granting " + perm + " to old pkg "
-                        + pkg.packageName);
+                        + pkg.getPackageName());
                 break;
             }
         }
@@ -3014,29 +3028,26 @@
      *
      * <p>This handles parent/child apps.
      */
-    private boolean hasPrivappWhitelistEntry(String perm, PackageParser.Package pkg) {
-        ArraySet<String> wlPermissions = null;
+    private boolean hasPrivappWhitelistEntry(String perm, AndroidPackage pkg) {
+        ArraySet<String> wlPermissions;
         if (pkg.isVendor()) {
             wlPermissions =
-                    SystemConfig.getInstance().getVendorPrivAppPermissions(pkg.packageName);
+                    SystemConfig.getInstance().getVendorPrivAppPermissions(pkg.getPackageName());
         } else if (pkg.isProduct()) {
             wlPermissions =
-                    SystemConfig.getInstance().getProductPrivAppPermissions(pkg.packageName);
+                    SystemConfig.getInstance().getProductPrivAppPermissions(pkg.getPackageName());
         } else if (pkg.isSystemExt()) {
             wlPermissions =
                     SystemConfig.getInstance().getSystemExtPrivAppPermissions(
-                            pkg.packageName);
+                            pkg.getPackageName());
         } else {
-            wlPermissions = SystemConfig.getInstance().getPrivAppPermissions(pkg.packageName);
+            wlPermissions = SystemConfig.getInstance().getPrivAppPermissions(pkg.getPackageName());
         }
-        // Let's check if this package is whitelisted...
-        boolean whitelisted = wlPermissions != null && wlPermissions.contains(perm);
-        // If it's not, we'll also tail-recurse to the parent.
-        return whitelisted ||
-                pkg.parentPackage != null && hasPrivappWhitelistEntry(perm, pkg.parentPackage);
+
+        return wlPermissions != null && wlPermissions.contains(perm);
     }
 
-    private boolean grantSignaturePermission(String perm, PackageParser.Package pkg,
+    private boolean grantSignaturePermission(String perm, AndroidPackage pkg,
             BasePermission bp, PermissionsState origPermissions) {
         boolean oemPermission = bp.isOEM();
         boolean vendorPrivilegedPermission = bp.isVendorPrivileged();
@@ -3044,7 +3055,7 @@
         boolean privappPermissionsDisable =
                 RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS_DISABLE;
         boolean platformPermission = PLATFORM_PACKAGE_NAME.equals(bp.getSourcePackageName());
-        boolean platformPackage = PLATFORM_PACKAGE_NAME.equals(pkg.packageName);
+        boolean platformPackage = PLATFORM_PACKAGE_NAME.equals(pkg.getPackageName());
         if (!privappPermissionsDisable && privilegedPermission && pkg.isPrivileged()
                 && !platformPackage && platformPermission) {
             if (!hasPrivappWhitelistEntry(perm, pkg)) {
@@ -3054,22 +3065,22 @@
                     ArraySet<String> deniedPermissions = null;
                     if (pkg.isVendor()) {
                         deniedPermissions = SystemConfig.getInstance()
-                                .getVendorPrivAppDenyPermissions(pkg.packageName);
+                                .getVendorPrivAppDenyPermissions(pkg.getPackageName());
                     } else if (pkg.isProduct()) {
                         deniedPermissions = SystemConfig.getInstance()
-                                .getProductPrivAppDenyPermissions(pkg.packageName);
+                                .getProductPrivAppDenyPermissions(pkg.getPackageName());
                     } else if (pkg.isSystemExt()) {
                         deniedPermissions = SystemConfig.getInstance()
-                                .getSystemExtPrivAppDenyPermissions(pkg.packageName);
+                                .getSystemExtPrivAppDenyPermissions(pkg.getPackageName());
                     } else {
                         deniedPermissions = SystemConfig.getInstance()
-                                .getPrivAppDenyPermissions(pkg.packageName);
+                                .getPrivAppDenyPermissions(pkg.getPackageName());
                     }
                     final boolean permissionViolation =
                             deniedPermissions == null || !deniedPermissions.contains(perm);
                     if (permissionViolation) {
                         Slog.w(TAG, "Privileged permission " + perm + " for package "
-                                + pkg.packageName + " (" + pkg.codePath
+                                + pkg.getPackageName() + " (" + pkg.getCodePath()
                                 + ") not in privapp-permissions whitelist");
 
                         if (RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS_ENFORCE) {
@@ -3077,7 +3088,7 @@
                                 mPrivappPermissionsViolations = new ArraySet<>();
                             }
                             mPrivappPermissionsViolations.add(
-                                    pkg.packageName + " (" + pkg.codePath + "): " + perm);
+                                    pkg.getPackageName() + " (" + pkg.getCodePath() + "): " + perm);
                         }
                     } else {
                         return false;
@@ -3102,24 +3113,23 @@
         //       package, and the defining package still trusts the old certificate for permissions
         //     - or it shares the above relationships with the system package
         boolean allowed =
-                pkg.mSigningDetails.hasAncestorOrSelf(
+                pkg.getSigningDetails().hasAncestorOrSelf(
                         bp.getSourcePackageSetting().getSigningDetails())
                 || bp.getSourcePackageSetting().getSigningDetails().checkCapability(
-                        pkg.mSigningDetails,
+                        pkg.getSigningDetails(),
                         PackageParser.SigningDetails.CertCapabilities.PERMISSION)
-                || pkg.mSigningDetails.hasAncestorOrSelf(systemPackage.mSigningDetails)
-                || systemPackage.mSigningDetails.checkCapability(
-                        pkg.mSigningDetails,
+                || pkg.getSigningDetails().hasAncestorOrSelf(systemPackage.getSigningDetails())
+                || systemPackage.getSigningDetails().checkCapability(
+                        pkg.getSigningDetails(),
                         PackageParser.SigningDetails.CertCapabilities.PERMISSION);
         if (!allowed && (privilegedPermission || oemPermission)) {
             if (pkg.isSystem()) {
                 // For updated system applications, a privileged/oem permission
                 // is granted only if it had been defined by the original application.
                 if (pkg.isUpdatedSystemApp()) {
-                    final PackageParser.Package disabledPkg =
-                            mPackageManagerInt.getDisabledSystemPackage(pkg.packageName);
-                    final PackageSetting disabledPs =
-                            (disabledPkg != null) ? (PackageSetting) disabledPkg.mExtras : null;
+                    final PackageSetting disabledPs = (PackageSetting) mPackageManagerInt
+                            .getDisabledSystemPackage(pkg.getPackageName());
+                    final AndroidPackage disabledPkg = disabledPs == null ? null : disabledPs.pkg;
                     if (disabledPs != null
                             && disabledPs.getPermissionsState().hasInstallPermission(perm)) {
                         // If the original was granted this permission, we take
@@ -3144,40 +3154,10 @@
                                                 && canGrantOemPermission(disabledPs, perm)))) {
                             allowed = true;
                         }
-                        // Also if a privileged parent package on the system image or any of
-                        // its children requested a privileged/oem permission, the updated child
-                        // packages can also get the permission.
-                        if (pkg.parentPackage != null) {
-                            final PackageParser.Package disabledParentPkg = mPackageManagerInt
-                                    .getDisabledSystemPackage(pkg.parentPackage.packageName);
-                            final PackageSetting disabledParentPs = (disabledParentPkg != null)
-                                    ? (PackageSetting) disabledParentPkg.mExtras : null;
-                            if (disabledParentPkg != null
-                                    && ((privilegedPermission && disabledParentPs.isPrivileged())
-                                            || (oemPermission && disabledParentPs.isOem()))) {
-                                if (isPackageRequestingPermission(disabledParentPkg, perm)
-                                        && canGrantOemPermission(disabledParentPs, perm)) {
-                                    allowed = true;
-                                } else if (disabledParentPkg.childPackages != null) {
-                                    for (PackageParser.Package disabledChildPkg
-                                            : disabledParentPkg.childPackages) {
-                                        final PackageSetting disabledChildPs =
-                                                (disabledChildPkg != null)
-                                                        ? (PackageSetting) disabledChildPkg.mExtras
-                                                        : null;
-                                        if (isPackageRequestingPermission(disabledChildPkg, perm)
-                                                && canGrantOemPermission(
-                                                        disabledChildPs, perm)) {
-                                            allowed = true;
-                                            break;
-                                        }
-                                    }
-                                }
-                            }
-                        }
                     }
                 } else {
-                    final PackageSetting ps = (PackageSetting) pkg.mExtras;
+                    final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting(
+                            pkg.getPackageName());
                     allowed = (privilegedPermission && pkg.isPrivileged())
                             || (oemPermission && pkg.isOem()
                                     && canGrantOemPermission(ps, perm));
@@ -3188,7 +3168,8 @@
                 if (allowed && privilegedPermission &&
                         !vendorPrivilegedPermission && pkg.isVendor()) {
                    Slog.w(TAG, "Permission " + perm + " cannot be granted to privileged vendor apk "
-                           + pkg.packageName + " because it isn't a 'vendorPrivileged' permission.");
+                           + pkg.getPackageName()
+                           + " because it isn't a 'vendorPrivileged' permission.");
                    allowed = false;
                 }
             }
@@ -3196,7 +3177,7 @@
         if (!allowed) {
             if (!allowed
                     && bp.isPre23()
-                    && pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) {
+                    && pkg.getTargetSdkVersion() < Build.VERSION_CODES.M) {
                 // If this was a previously normal/dangerous permission that got moved
                 // to a system permission as part of the runtime permission redesign, then
                 // we still want to blindly grant it to old apps.
@@ -3310,26 +3291,27 @@
         return Boolean.TRUE == granted;
     }
 
-    private boolean isPermissionsReviewRequired(@NonNull PackageParser.Package pkg,
+    private boolean isPermissionsReviewRequired(@NonNull AndroidPackage pkg,
             @UserIdInt int userId) {
         // Permission review applies only to apps not supporting the new permission model.
-        if (pkg.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.M) {
+        if (pkg.getTargetSdkVersion() >= Build.VERSION_CODES.M) {
             return false;
         }
 
         // Legacy apps have the permission and get user consent on launch.
-        if (pkg.mExtras == null) {
+        final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting(
+                pkg.getPackageName());
+        if (ps == null) {
             return false;
         }
-        final PackageSetting ps = (PackageSetting) pkg.mExtras;
         final PermissionsState permissionsState = ps.getPermissionsState();
         return permissionsState.isPermissionReviewRequired(userId);
     }
 
-    private boolean isPackageRequestingPermission(PackageParser.Package pkg, String permission) {
-        final int permCount = pkg.requestedPermissions.size();
+    private boolean isPackageRequestingPermission(AndroidPackage pkg, String permission) {
+        final int permCount = pkg.getRequestedPermissions().size();
         for (int j = 0; j < permCount; j++) {
-            String requestedPermission = pkg.requestedPermissions.get(j);
+            String requestedPermission = pkg.getRequestedPermissions().get(j);
             if (permission.equals(requestedPermission)) {
                 return true;
             }
@@ -3337,41 +3319,7 @@
         return false;
     }
 
-    @GuardedBy("mLock")
-    private void grantRuntimePermissionsGrantedToDisabledPackageLocked(
-            PackageParser.Package pkg, int callingUid, PermissionCallback callback) {
-        if (pkg.parentPackage == null) {
-            return;
-        }
-        if (pkg.requestedPermissions == null) {
-            return;
-        }
-        final PackageParser.Package disabledPkg =
-                mPackageManagerInt.getDisabledSystemPackage(pkg.parentPackage.packageName);
-        if (disabledPkg == null || disabledPkg.mExtras == null) {
-            return;
-        }
-        final PackageSetting disabledPs = (PackageSetting) disabledPkg.mExtras;
-        if (!disabledPs.isPrivileged() || disabledPs.hasChildPackages()) {
-            return;
-        }
-        final int permCount = pkg.requestedPermissions.size();
-        for (int i = 0; i < permCount; i++) {
-            String permission = pkg.requestedPermissions.get(i);
-            BasePermission bp = mSettings.getPermissionLocked(permission);
-            if (bp == null || !(bp.isRuntime() || bp.isDevelopment())) {
-                continue;
-            }
-            for (int userId : mUserManagerInt.getUserIds()) {
-                if (disabledPs.getPermissionsState().hasRuntimePermission(permission, userId)) {
-                    grantRuntimePermissionInternal(
-                            permission, pkg.packageName, false, callingUid, userId, callback);
-                }
-            }
-        }
-    }
-
-    private void grantRequestedRuntimePermissions(PackageParser.Package pkg, int[] userIds,
+    private void grantRequestedRuntimePermissions(AndroidPackage pkg, int[] userIds,
             String[] grantedPermissions, int callingUid, PermissionCallback callback) {
         for (int userId : userIds) {
             grantRequestedRuntimePermissionsForUser(pkg, userId, grantedPermissions, callingUid,
@@ -3379,9 +3327,10 @@
         }
     }
 
-    private void grantRequestedRuntimePermissionsForUser(PackageParser.Package pkg, int userId,
+    private void grantRequestedRuntimePermissionsForUser(AndroidPackage pkg, int userId,
             String[] grantedPermissions, int callingUid, PermissionCallback callback) {
-        PackageSetting ps = (PackageSetting) pkg.mExtras;
+        PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting(
+                pkg.getPackageName());
         if (ps == null) {
             return;
         }
@@ -3394,12 +3343,12 @@
         final int compatFlags = PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED
                 | PackageManager.FLAG_PERMISSION_REVOKED_COMPAT;
 
-        final boolean supportsRuntimePermissions = pkg.applicationInfo.targetSdkVersion
+        final boolean supportsRuntimePermissions = pkg.getTargetSdkVersion()
                 >= Build.VERSION_CODES.M;
 
-        final boolean instantApp = mPackageManagerInt.isInstantApp(pkg.packageName, userId);
+        final boolean instantApp = mPackageManagerInt.isInstantApp(pkg.getPackageName(), userId);
 
-        for (String permission : pkg.requestedPermissions) {
+        for (String permission : pkg.getRequestedPermissions()) {
             final BasePermission bp;
             synchronized (mLock) {
                 bp = mSettings.getPermissionLocked(permission);
@@ -3413,14 +3362,14 @@
                 if (supportsRuntimePermissions) {
                     // Installer cannot change immutable permissions.
                     if ((flags & immutableFlags) == 0) {
-                        grantRuntimePermissionInternal(permission, pkg.packageName, false,
+                        grantRuntimePermissionInternal(permission, pkg.getPackageName(), false,
                                 callingUid, userId, callback);
                     }
                 } else {
                     // In permission review mode we clear the review flag and the revoked compat
                     // flag when we are asked to install the app with all permissions granted.
                     if ((flags & compatFlags) != 0) {
-                        updatePermissionFlagsInternal(permission, pkg.packageName, compatFlags,
+                        updatePermissionFlagsInternal(permission, pkg.getPackageName(), compatFlags,
                                 0, callingUid, userId, false, callback);
                     }
                 }
@@ -3428,11 +3377,11 @@
         }
     }
 
-    private void setWhitelistedRestrictedPermissionsForUser(@NonNull PackageParser.Package pkg,
+    private void setWhitelistedRestrictedPermissionsForUser(@NonNull AndroidPackage pkg,
             @UserIdInt int userId, @Nullable List<String> permissions, int callingUid,
             @PermissionWhitelistFlags int whitelistFlags, PermissionCallback callback) {
         final PermissionsState permissionsState =
-                PackageManagerServiceUtils.getPermissionsState(pkg);
+                PackageManagerServiceUtils.getPermissionsState(mPackageManagerInt, pkg);
         if (permissionsState == null) {
             return;
         }
@@ -3440,9 +3389,9 @@
         ArraySet<String> oldGrantedRestrictedPermissions = null;
         boolean updatePermissions = false;
 
-        final int permissionCount = pkg.requestedPermissions.size();
+        final int permissionCount = pkg.getRequestedPermissions().size();
         for (int i = 0; i < permissionCount; i++) {
-            final String permissionName = pkg.requestedPermissions.get(i);
+            final String permissionName = pkg.getRequestedPermissions().get(i);
 
             final BasePermission bp = mSettings.getPermissionLocked(permissionName);
 
@@ -3518,19 +3467,19 @@
 
             // If we are whitelisting an app that does not support runtime permissions
             // we need to make sure it goes through the permission review UI at launch.
-            if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M
+            if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.M
                     && !wasWhitelisted && isWhitelisted) {
                 mask |= PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
                 newFlags |= PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
             }
 
-            updatePermissionFlagsInternal(permissionName, pkg.packageName, mask, newFlags,
+            updatePermissionFlagsInternal(permissionName, pkg.getPackageName(), mask, newFlags,
                     callingUid, userId, false, null /*callback*/);
         }
 
         if (updatePermissions) {
             // Update permission of this app to take into account the new whitelist state.
-            restorePermissionState(pkg, false, pkg.packageName, callback);
+            restorePermissionState(pkg, false, pkg.getPackageName(), callback);
 
             // If this resulted in losing a permission we need to kill the app.
             if (oldGrantedRestrictedPermissions != null) {
@@ -3539,9 +3488,9 @@
                     final String permission = oldGrantedRestrictedPermissions.valueAt(i);
                     // Sometimes we create a new permission state instance during update.
                     final PermissionsState newPermissionsState =
-                            PackageManagerServiceUtils.getPermissionsState(pkg);
+                            PackageManagerServiceUtils.getPermissionsState(mPackageManagerInt, pkg);
                     if (!newPermissionsState.hasPermission(permission, userId)) {
-                        callback.onPermissionRevoked(pkg.applicationInfo.uid, userId);
+                        callback.onPermissionRevoked(pkg.getUid(), userId);
                         break;
                     }
                 }
@@ -3554,17 +3503,17 @@
             SharedUserSetting suSetting, int[] allUserIds) {
         // Collect all used permissions in the UID
         final ArraySet<String> usedPermissions = new ArraySet<>();
-        final List<PackageParser.Package> pkgList = suSetting.getPackages();
+        final List<AndroidPackage> pkgList = suSetting.getPackages();
         if (pkgList == null || pkgList.size() == 0) {
             return EmptyArray.INT;
         }
-        for (PackageParser.Package pkg : pkgList) {
-            if (pkg.requestedPermissions == null) {
+        for (AndroidPackage pkg : pkgList) {
+            if (pkg.getRequestedPermissions() == null) {
                 continue;
             }
-            final int requestedPermCount = pkg.requestedPermissions.size();
+            final int requestedPermCount = pkg.getRequestedPermissions().size();
             for (int j = 0; j < requestedPermCount; j++) {
-                String permission = pkg.requestedPermissions.get(j);
+                String permission = pkg.getRequestedPermissions().get(j);
                 BasePermission bp = mSettings.getPermissionLocked(permission);
                 if (bp != null) {
                     usedPermissions.add(permission);
@@ -3626,18 +3575,12 @@
      * @param allPackages All currently known packages
      * @param callback Callback to call after permission changes
      */
-    private void updatePermissions(@NonNull String packageName, @Nullable PackageParser.Package pkg,
+    private void updatePermissions(@NonNull String packageName, @Nullable AndroidPackage pkg,
             @NonNull PermissionCallback callback) {
         final int flags =
                 (pkg != null ? UPDATE_PERMISSIONS_ALL | UPDATE_PERMISSIONS_REPLACE_PKG : 0);
         updatePermissions(
                 packageName, pkg, getVolumeUuidForPackage(pkg), flags, callback);
-        if (pkg != null && pkg.childPackages != null) {
-            for (PackageParser.Package childPkg : pkg.childPackages) {
-                updatePermissions(childPkg.packageName, childPkg,
-                        getVolumeUuidForPackage(childPkg), flags, callback);
-            }
-        }
     }
 
     /**
@@ -3673,10 +3616,9 @@
                 // Only system declares background permissions, hence mapping does never change.
                 mBackgroundPermissions = new ArrayMap<>();
                 for (BasePermission bp : mSettings.getAllPermissionsLocked()) {
-                    if (bp.perm != null && bp.perm.info != null
-                            && bp.perm.info.backgroundPermission != null) {
+                    if (bp.perm != null && bp.perm.backgroundPermission != null) {
                         String fgPerm = bp.name;
-                        String bgPerm = bp.perm.info.backgroundPermission;
+                        String bgPerm = bp.perm.backgroundPermission;
 
                         List<String> fgPerms = mBackgroundPermissions.get(bgPerm);
                         if (fgPerms == null) {
@@ -3737,7 +3679,7 @@
      * @param callback Callback to call after permission changes
      */
     private void updatePermissions(final @Nullable String changingPkgName,
-            final @Nullable PackageParser.Package changingPkg,
+            final @Nullable AndroidPackage changingPkg,
             final @Nullable String replaceVolumeUuid,
             @UpdatePermissionFlags int flags,
             final @Nullable PermissionCallback callback) {
@@ -3770,7 +3712,7 @@
         // Now update the permissions for all packages.
         if ((flags & UPDATE_PERMISSIONS_ALL) != 0) {
             final boolean replaceAll = ((flags & UPDATE_PERMISSIONS_REPLACE_ALL) != 0);
-            mPackageManagerInt.forEachPackage((Package pkg) -> {
+            mPackageManagerInt.forEachPackage((AndroidPackage pkg) -> {
                 if (pkg == changingPkg) {
                     return;
                 }
@@ -3809,7 +3751,7 @@
      * @return {@code true} if a permission source package might have changed
      */
     private boolean updatePermissionSourcePackage(@Nullable String packageName,
-            @Nullable PackageParser.Package pkg,
+            @Nullable AndroidPackage pkg,
             final @Nullable PermissionCallback callback) {
         boolean changed = false;
 
@@ -3832,8 +3774,8 @@
                             for (int userIdNum = 0; userIdNum < numUserIds; userIdNum++) {
                                 final int userId = userIds[userIdNum];
 
-                                mPackageManagerInt.forEachPackage((Package p) -> {
-                                    final String pName = p.packageName;
+                                mPackageManagerInt.forEachPackage((AndroidPackage p) -> {
+                                    final String pName = p.getPackageName();
                                     final ApplicationInfo appInfo =
                                             mPackageManagerInt.getApplicationInfo(pName, 0,
                                                     Process.SYSTEM_UID, UserHandle.USER_SYSTEM);
@@ -3878,11 +3820,13 @@
         }
         if (needsUpdate != null) {
             for (final BasePermission bp : needsUpdate) {
-                final PackageParser.Package sourcePkg =
+                final AndroidPackage sourcePkg =
                         mPackageManagerInt.getPackage(bp.getSourcePackageName());
+                final PackageSetting sourcePs =
+                        (PackageSetting) mPackageManagerInt.getPackageSetting(
+                                bp.getSourcePackageName());
                 synchronized (mLock) {
-                    if (sourcePkg != null && sourcePkg.mExtras != null) {
-                        final PackageSetting sourcePs = (PackageSetting) sourcePkg.mExtras;
+                    if (sourcePkg != null && sourcePs != null) {
                         if (bp.getSourcePackageSetting() == null) {
                             bp.setSourcePackageSetting(sourcePs);
                         }
@@ -3915,7 +3859,7 @@
      * @return {@code true} if a permission tree ownership might have changed
      */
     private boolean updatePermissionTreeSourcePackage(@Nullable String packageName,
-            @Nullable PackageParser.Package pkg) {
+            @Nullable AndroidPackage pkg) {
         boolean changed = false;
 
         Set<BasePermission> needsUpdate = null;
@@ -3941,11 +3885,13 @@
         }
         if (needsUpdate != null) {
             for (final BasePermission bp : needsUpdate) {
-                final PackageParser.Package sourcePkg =
+                final AndroidPackage sourcePkg =
                         mPackageManagerInt.getPackage(bp.getSourcePackageName());
+                final PackageSetting sourcePs =
+                        (PackageSetting) mPackageManagerInt.getPackageSetting(
+                                bp.getSourcePackageName());
                 synchronized (mLock) {
-                    if (sourcePkg != null && sourcePkg.mExtras != null) {
-                        final PackageSetting sourcePs = (PackageSetting) sourcePkg.mExtras;
+                    if (sourcePkg != null && sourcePs != null) {
                         if (bp.getSourcePackageSetting() == null) {
                             bp.setSourcePackageSetting(sourcePs);
                         }
@@ -4068,24 +4014,28 @@
         }
     }
 
-    private static String getVolumeUuidForPackage(PackageParser.Package pkg) {
+    private static String getVolumeUuidForPackage(AndroidPackage pkg) {
         if (pkg == null) {
             return StorageManager.UUID_PRIVATE_INTERNAL;
         }
         if (pkg.isExternal()) {
-            if (TextUtils.isEmpty(pkg.volumeUuid)) {
+            if (TextUtils.isEmpty(pkg.getVolumeUuid())) {
                 return StorageManager.UUID_PRIMARY_PHYSICAL;
             } else {
-                return pkg.volumeUuid;
+                return pkg.getVolumeUuid();
             }
         } else {
             return StorageManager.UUID_PRIVATE_INTERNAL;
         }
     }
 
-    private static boolean hasPermission(PackageParser.Package pkgInfo, String permName) {
-        for (int i=pkgInfo.permissions.size()-1; i>=0; i--) {
-            if (pkgInfo.permissions.get(i).info.name.equals(permName)) {
+    private static boolean hasPermission(AndroidPackage pkg, String permName) {
+        if (pkg.getPermissions() == null) {
+            return false;
+        }
+
+        for (int i = pkg.getPermissions().size() - 1; i >= 0; i--) {
+            if (pkg.getPermissions().get(i).getName().equals(permName)) {
                 return true;
             }
         }
@@ -4124,37 +4074,39 @@
             PermissionManagerService.this.systemReady();
         }
         @Override
-        public boolean isPermissionsReviewRequired(@NonNull Package pkg, @UserIdInt int userId) {
+        public boolean isPermissionsReviewRequired(@NonNull AndroidPackage pkg,
+                @UserIdInt int userId) {
             return PermissionManagerService.this.isPermissionsReviewRequired(pkg, userId);
         }
+
         @Override
         public void revokeRuntimePermissionsIfGroupChanged(
-                @NonNull PackageParser.Package newPackage,
-                @NonNull PackageParser.Package oldPackage,
+                @NonNull AndroidPackage newPackage,
+                @NonNull AndroidPackage oldPackage,
                 @NonNull ArrayList<String> allPackageNames) {
             PermissionManagerService.this.revokeRuntimePermissionsIfGroupChanged(newPackage,
                     oldPackage, allPackageNames, mDefaultPermissionCallback);
         }
         @Override
-        public void addAllPermissions(Package pkg, boolean chatty) {
+        public void addAllPermissions(AndroidPackage pkg, boolean chatty) {
             PermissionManagerService.this.addAllPermissions(pkg, chatty);
         }
         @Override
-        public void addAllPermissionGroups(Package pkg, boolean chatty) {
+        public void addAllPermissionGroups(AndroidPackage pkg, boolean chatty) {
             PermissionManagerService.this.addAllPermissionGroups(pkg, chatty);
         }
         @Override
-        public void removeAllPermissions(Package pkg, boolean chatty) {
+        public void removeAllPermissions(AndroidPackage pkg, boolean chatty) {
             PermissionManagerService.this.removeAllPermissions(pkg, chatty);
         }
         @Override
-        public void grantRequestedRuntimePermissions(PackageParser.Package pkg, int[] userIds,
+        public void grantRequestedRuntimePermissions(AndroidPackage pkg, int[] userIds,
                 String[] grantedPermissions, int callingUid) {
             PermissionManagerService.this.grantRequestedRuntimePermissions(
                     pkg, userIds, grantedPermissions, callingUid, mDefaultPermissionCallback);
         }
         @Override
-        public void setWhitelistedRestrictedPermissions(@NonNull PackageParser.Package pkg,
+        public void setWhitelistedRestrictedPermissions(@NonNull AndroidPackage pkg,
                 @NonNull int[] userIds, @Nullable List<String> permissions, int callingUid,
                 @PackageManager.PermissionWhitelistFlags int flags) {
             for (int userId : userIds) {
@@ -4169,13 +4121,7 @@
                     packageName, permissions, flags, userId);
         }
         @Override
-        public void grantRuntimePermissionsGrantedToDisabledPackage(PackageParser.Package pkg,
-                int callingUid) {
-            PermissionManagerService.this.grantRuntimePermissionsGrantedToDisabledPackageLocked(
-                    pkg, callingUid, mDefaultPermissionCallback);
-        }
-        @Override
-        public void updatePermissions(@NonNull String packageName, @Nullable Package pkg) {
+        public void updatePermissions(@NonNull String packageName, @Nullable AndroidPackage pkg) {
             PermissionManagerService.this
                     .updatePermissions(packageName, pkg, mDefaultPermissionCallback);
         }
@@ -4185,13 +4131,13 @@
                     .updateAllPermissions(volumeUuid, sdkUpdated, mDefaultPermissionCallback);
         }
         @Override
-        public void resetRuntimePermissions(Package pkg, int userId) {
+        public void resetRuntimePermissions(AndroidPackage pkg, int userId) {
             PermissionManagerService.this.resetRuntimePermissionsInternal(pkg, userId);
         }
         @Override
         public void resetAllRuntimePermissions(final int userId) {
             mPackageManagerInt.forEachPackage(
-                    (PackageParser.Package pkg) -> resetRuntimePermissionsInternal(pkg, userId));
+                    (AndroidPackage pkg) -> resetRuntimePermissionsInternal(pkg, userId));
         }
         @Override
         public String[] getAppOpPermissionPackages(String permName, int callingUid) {
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
index fb5c6fdd..0f22619 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
@@ -21,8 +21,8 @@
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.content.pm.PackageManager;
-import android.content.pm.PackageParser;
 import android.content.pm.PermissionInfo;
+import android.content.pm.parsing.AndroidPackage;
 import android.permission.PermissionManagerInternal;
 
 import java.util.ArrayList;
@@ -175,16 +175,14 @@
 
     public abstract void systemReady();
 
-    public abstract boolean isPermissionsReviewRequired(@NonNull PackageParser.Package pkg,
+    public abstract boolean isPermissionsReviewRequired(@NonNull AndroidPackage pkg,
             @UserIdInt int userId);
 
-    public abstract void grantRuntimePermissionsGrantedToDisabledPackage(
-            @NonNull PackageParser.Package pkg, int callingUid);
     public abstract void grantRequestedRuntimePermissions(
-            @NonNull PackageParser.Package pkg, @NonNull int[] userIds,
+            @NonNull AndroidPackage pkg, @NonNull int[] userIds,
             @NonNull String[] grantedPermissions, int callingUid);
     public abstract void setWhitelistedRestrictedPermissions(
-            @NonNull PackageParser.Package pkg, @NonNull int[] userIds,
+            @NonNull AndroidPackage pkg, @NonNull int[] userIds,
             @NonNull List<String> permissions, int callingUid,
             @PackageManager.PermissionWhitelistFlags int whitelistFlags);
     /** Sets the whitelisted, restricted permissions for the given package. */
@@ -206,7 +204,7 @@
      * @param callback Callback to call after permission changes
      */
     public abstract void updatePermissions(@NonNull String packageName,
-            @Nullable PackageParser.Package pkg);
+            @Nullable AndroidPackage pkg);
 
     /**
      * Update all permissions for all apps.
@@ -226,7 +224,7 @@
      * Resets any user permission state changes (eg. permissions and flags) of all
      * packages installed for the given user.
      *
-     * @see #resetRuntimePermissions(android.content.pm.PackageParser.Package, int)
+     * @see #resetRuntimePermissions(AndroidPackage, int)
      */
     public abstract void resetAllRuntimePermissions(@UserIdInt int userId);
 
@@ -234,7 +232,7 @@
      * Resets any user permission state changes (eg. permissions and flags) of the
      * specified package for the given user.
      */
-    public abstract void resetRuntimePermissions(@NonNull PackageParser.Package pkg,
+    public abstract void resetRuntimePermissions(@NonNull AndroidPackage pkg,
             @UserIdInt int userId);
 
     /**
@@ -247,8 +245,8 @@
      * @param allPackageNames All packages
      */
     public abstract void revokeRuntimePermissionsIfGroupChanged(
-            @NonNull PackageParser.Package newPackage,
-            @NonNull PackageParser.Package oldPackage,
+            @NonNull AndroidPackage newPackage,
+            @NonNull AndroidPackage oldPackage,
             @NonNull ArrayList<String> allPackageNames);
 
     /**
@@ -257,9 +255,9 @@
      * NOTE: argument {@code groupTEMP} is temporary until mPermissionGroups is moved to
      * the permission settings.
      */
-    public abstract void addAllPermissions(@NonNull PackageParser.Package pkg, boolean chatty);
-    public abstract void addAllPermissionGroups(@NonNull PackageParser.Package pkg, boolean chatty);
-    public abstract void removeAllPermissions(@NonNull PackageParser.Package pkg, boolean chatty);
+    public abstract void addAllPermissions(@NonNull AndroidPackage pkg, boolean chatty);
+    public abstract void addAllPermissionGroups(@NonNull AndroidPackage pkg, boolean chatty);
+    public abstract void removeAllPermissions(@NonNull AndroidPackage pkg, boolean chatty);
 
     /** Retrieve the packages that have requested the given app op permission */
     public abstract @Nullable String[] getAppOpPermissionPackages(
diff --git a/services/core/java/com/android/server/pm/permission/PermissionSettings.java b/services/core/java/com/android/server/pm/permission/PermissionSettings.java
index 3d8cf2d..254b720 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionSettings.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionSettings.java
@@ -18,7 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.content.pm.PackageParser;
+import android.content.pm.parsing.ComponentParseUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Log;
@@ -65,8 +65,8 @@
      * name to permission group object.
      */
     @GuardedBy("mLock")
-    final ArrayMap<String, PackageParser.PermissionGroup> mPermissionGroups =
-            new ArrayMap<String, PackageParser.PermissionGroup>();
+    final ArrayMap<String, ComponentParseUtils.ParsedPermissionGroup> mPermissionGroups =
+            new ArrayMap<>();
 
     /**
      * Set of packages that request a particular app op. The mapping is from permission
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java
index 9b9f93f..5f39f51 100644
--- a/services/core/java/com/android/server/policy/PermissionPolicyService.java
+++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java
@@ -37,8 +37,8 @@
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.PackageManagerInternal.PackageListObserver;
-import android.content.pm.PackageParser;
 import android.content.pm.PermissionInfo;
+import android.content.pm.parsing.AndroidPackage;
 import android.os.Build;
 import android.os.Process;
 import android.os.RemoteException;
@@ -357,10 +357,10 @@
                 pkg.sharedUserId, userId);
         if (sharedPkgNames != null) {
             for (String sharedPkgName : sharedPkgNames) {
-                final PackageParser.Package sharedPkg = packageManagerInternal
+                final AndroidPackage sharedPkg = packageManagerInternal
                         .getPackage(sharedPkgName);
                 if (sharedPkg != null) {
-                    synchroniser.addPackage(sharedPkg.packageName);
+                    synchroniser.addPackage(sharedPkg.getPackageName());
                 }
             }
         }
@@ -377,7 +377,8 @@
                 PackageManagerInternal.class);
         final PermissionToOpSynchroniser synchronizer = new PermissionToOpSynchroniser(
                 getUserContext(getContext(), UserHandle.of(userId)));
-        packageManagerInternal.forEachPackage((pkg) -> synchronizer.addPackage(pkg.packageName));
+        packageManagerInternal.forEachPackage(
+                (pkg) -> synchronizer.addPackage(pkg.getPackageName()));
         synchronizer.syncPackages();
     }
 
diff --git a/services/core/java/com/android/server/role/RoleManagerService.java b/services/core/java/com/android/server/role/RoleManagerService.java
index aac0f90..a4eef9b 100644
--- a/services/core/java/com/android/server/role/RoleManagerService.java
+++ b/services/core/java/com/android/server/role/RoleManagerService.java
@@ -308,12 +308,12 @@
         ByteArrayOutputStream out = new ByteArrayOutputStream();
 
         pm.forEachInstalledPackage(FunctionalUtils.uncheckExceptions(pkg -> {
-            out.write(pkg.packageName.getBytes());
+            out.write(pkg.getPackageName().getBytes());
             out.write(BitUtils.toBytes(pkg.getLongVersionCode()));
-            out.write(pm.getApplicationEnabledState(pkg.packageName, userId));
+            out.write(pm.getApplicationEnabledState(pkg.getPackageName(), userId));
 
             ArraySet<String> enabledComponents =
-                    pm.getEnabledComponents(pkg.packageName, userId);
+                    pm.getEnabledComponents(pkg.getPackageName(), userId);
             int numComponents = CollectionUtils.size(enabledComponents);
             out.write(numComponents);
             for (int i = 0; i < numComponents; i++) {
@@ -321,12 +321,12 @@
             }
 
             ArraySet<String> disabledComponents =
-                    pm.getDisabledComponents(pkg.packageName, userId);
+                    pm.getDisabledComponents(pkg.getPackageName(), userId);
             numComponents = CollectionUtils.size(disabledComponents);
             for (int i = 0; i < numComponents; i++) {
                 out.write(disabledComponents.valueAt(i).getBytes());
             }
-            for (Signature signature : pkg.mSigningDetails.signatures) {
+            for (Signature signature : pkg.getSigningDetails().signatures) {
                 out.write(signature.toByteArray());
             }
         }), userId);
diff --git a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
index f6fb6e2..9d2a460 100644
--- a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
@@ -26,7 +26,6 @@
 import android.annotation.Nullable;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageParser;
 import android.os.Build;
@@ -51,17 +50,29 @@
 
     private ArrayMap<String, PackageSetting> mExisting = new ArrayMap<>();
 
-    private static PackageBuilder pkg(String packageName) {
-        return new PackageBuilder(packageName)
-                .setApplicationInfoTargetSdkVersion(Build.VERSION_CODES.R);
+    private static ParsingPackage pkg(String packageName) {
+        return PackageImpl.forParsing(packageName)
+                .setTargetSdkVersion(Build.VERSION_CODES.R);
     }
 
-    private static PackageBuilder pkg(String packageName, Intent... queries) {
-        return pkg(packageName).setQueriesIntents(queries);
+    private static ParsingPackage pkg(String packageName, Intent... queries) {
+        ParsingPackage pkg = pkg(packageName);
+        if (queries != null) {
+            for (Intent intent : queries) {
+                pkg.addQueriesIntent(intent);
+            }
+        }
+        return pkg;
     }
 
-    private static PackageBuilder pkg(String packageName, String... queriesPackages) {
-        return pkg(packageName).setQueriesPackages(queriesPackages);
+    private static ParsingPackage pkg(String packageName, String... queriesPackages) {
+        ParsingPackage pkg = pkg(packageName);
+        if (queriesPackages != null) {
+            for (String queryPackageName : queriesPackages) {
+                pkg.addQueriesPackage(queryPackageName);
+            }
+        }
+        return pkg;
     }
 
     private static PackageBuilder pkg(String packageName, IntentFilter... filters) {
@@ -89,7 +100,9 @@
                 return info;
             });
         }
-        return packageBuilder;
+
+        return pkg(packageName)
+                .addActivity(activity);
     }
 
     @Before
@@ -98,7 +111,7 @@
 
         MockitoAnnotations.initMocks(this);
         when(mFeatureConfigMock.isGloballyEnabled()).thenReturn(true);
-        when(mFeatureConfigMock.packageIsEnabled(any(PackageParser.Package.class)))
+        when(mFeatureConfigMock.packageIsEnabled(any(AndroidPackage.class)))
                 .thenReturn(true);
     }
 
@@ -238,7 +251,7 @@
 
     @Test
     public void testNoQueries_FeatureOff_DoesntFilter() {
-        when(mFeatureConfigMock.packageIsEnabled(any(PackageParser.Package.class)))
+        when(mFeatureConfigMock.packageIsEnabled(any(AndroidPackage.class)))
                 .thenReturn(false);
         final AppsFilter appsFilter =
                 new AppsFilter(mFeatureConfigMock, new String[]{}, false);
diff --git a/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java
index fec3267..0273a1c 100644
--- a/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java
@@ -19,17 +19,17 @@
 
 import android.content.pm.PackageParser;
 import android.content.pm.Signature;
+import android.test.AndroidTestCase;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.LongSparseArray;
+
 import com.android.internal.util.ArrayUtils;
 
 import java.io.File;
 import java.io.IOException;
-import java.security.cert.CertificateException;
 import java.security.PublicKey;
-
-import android.test.AndroidTestCase;
+import java.security.cert.CertificateException;
 
 public class KeySetManagerServiceTest extends AndroidTestCase {
 
@@ -39,7 +39,7 @@
     public PackageSetting generateFakePackageSetting(String name) {
         return new PackageSetting(name, name, new File(mContext.getCacheDir(), "fakeCodePath"),
                 new File(mContext.getCacheDir(), "fakeResPath"), "", "", "",
-                "", 1, 0, 0, null, null, 0 /*sharedUserId*/, null /*usesStaticLibraries*/,
+                "", 1, 0, 0, 0 /*sharedUserId*/, null /*usesStaticLibraries*/,
                 null /*usesStaticLibrariesVersions*/);
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageBuilder.java b/services/tests/servicestests/src/com/android/server/pm/PackageBuilder.java
deleted file mode 100644
index c38672c..0000000
--- a/services/tests/servicestests/src/com/android/server/pm/PackageBuilder.java
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.pm;
-
-import android.content.Intent;
-import android.content.pm.ActivityInfo;
-import android.content.pm.PackageParser;
-
-import com.android.internal.util.ArrayUtils;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-
-class PackageBuilder {
-    final PackageParser.Package mPkg;
-
-    PackageBuilder(String packageName) {
-        mPkg = new PackageParser.Package(packageName);
-    }
-
-    PackageBuilder setApplicationInfoCodePath(String codePath) {
-        mPkg.applicationInfo.setCodePath(codePath);
-        return this;
-    }
-
-    PackageBuilder setApplicationInfoResourcePath(String resourcePath) {
-        mPkg.applicationInfo.setResourcePath(resourcePath);
-        return this;
-    }
-
-    PackageBuilder setCodePath(String codePath) {
-        mPkg.codePath = codePath;
-        return this;
-    }
-
-    PackageBuilder setBaseCodePath(String baseCodePath) {
-        mPkg.baseCodePath = baseCodePath;
-        return this;
-    }
-
-    PackageBuilder addUsesStaticLibrary(String name, long version) {
-        mPkg.usesStaticLibraries = ArrayUtils.add(mPkg.usesStaticLibraries, name);
-        mPkg.usesStaticLibrariesVersions =
-                ArrayUtils.appendLong(mPkg.usesStaticLibrariesVersions, version);
-        return this;
-    }
-
-    PackageBuilder setApplicationInfoNativeLibraryRootDir(String dir) {
-        mPkg.applicationInfo.nativeLibraryRootDir = dir;
-        return this;
-    }
-
-    PackageBuilder setStaticSharedLib(String staticSharedLibName, long staticSharedLibVersion) {
-        mPkg.staticSharedLibVersion = staticSharedLibVersion;
-        mPkg.staticSharedLibName = staticSharedLibName;
-        return this;
-    }
-
-    PackageBuilder setManifestPackageName(String manifestPackageName) {
-        mPkg.manifestPackageName = manifestPackageName;
-        return this;
-    }
-
-    PackageBuilder setVersionCodeMajor(int versionCodeMajor) {
-        mPkg.mVersionCodeMajor = versionCodeMajor;
-        return this;
-    }
-
-    PackageBuilder setVersionCode(int versionCode) {
-        mPkg.mVersionCode = versionCode;
-        return this;
-    }
-
-    PackageBuilder addSplitCodePath(String splitCodePath) {
-        mPkg.splitCodePaths =
-                ArrayUtils.appendElement(String.class, mPkg.splitCodePaths, splitCodePath);
-        return this;
-    }
-
-    PackageBuilder setApplicationInfoVolumeUuid(String volumeUuid) {
-        mPkg.applicationInfo.volumeUuid = volumeUuid;
-        return this;
-    }
-
-    PackageBuilder addLibraryName(String libraryName) {
-        mPkg.libraryNames = ArrayUtils.add(mPkg.libraryNames, libraryName);
-        return this;
-    }
-
-    PackageBuilder setRealPackageName(String realPackageName) {
-        mPkg.mRealPackage = realPackageName;
-        return this;
-    }
-
-    PackageBuilder setCpuAbiOVerride(String cpuAbiOverride) {
-        mPkg.cpuAbiOverride = cpuAbiOverride;
-        return this;
-    }
-
-    PackageBuilder addPermissionRequest(String permissionName) {
-        mPkg.requestedPermissions.add(permissionName);
-        return this;
-    }
-
-    PackageParser.Package build() {
-        return mPkg;
-    }
-
-    public PackageBuilder addApplicationInfoFlag(int flag) {
-        mPkg.applicationInfo.flags |= flag;
-        return this;
-    }
-
-    public PackageBuilder setApplicationInfoTargetSdkVersion(int versionCode) {
-        mPkg.applicationInfo.targetSdkVersion = versionCode;
-        return this;
-    }
-
-    public PackageBuilder setQueriesIntents(Collection<Intent> queriesIntents) {
-        mPkg.mQueriesIntents = new ArrayList<>(queriesIntents);
-        return this;
-    }
-
-    public PackageBuilder setQueriesIntents(Intent... intents) {
-        return setQueriesIntents(Arrays.asList(intents));
-    }
-
-    public PackageBuilder setQueriesPackages(Collection<String> queriesPackages) {
-        mPkg.mQueriesPackages = new ArrayList<>(queriesPackages);
-        return this;
-    }
-
-    public PackageBuilder setQueriesPackages(String... queriesPackages) {
-        return setQueriesPackages(Arrays.asList(queriesPackages));
-    }
-
-    public PackageBuilder setForceQueryable(boolean forceQueryable) {
-        mPkg.mForceQueryable = forceQueryable;
-        return this;
-    }
-
-    public interface ParseComponentArgsCreator {
-        PackageParser.ParseComponentArgs create(PackageParser.Package pkg);
-    }
-
-    public PackageBuilder addActivity(ParseComponentArgsCreator argsCreator, ActivityInfo info) {
-        mPkg.activities.add(new PackageParser.Activity(argsCreator.create(mPkg), info));
-        return this;
-    }
-
-    public interface ActivityIntentInfoCreator {
-        PackageParser.ActivityIntentInfo create(PackageParser.Activity activity);
-    }
-
-    public PackageBuilder addActivityIntentInfo(
-            int activityIndex, ActivityIntentInfoCreator creator) {
-        final PackageParser.Activity activity = mPkg.activities.get(activityIndex);
-        activity.intents.add(creator.create(activity));
-        return this;
-    }
-}
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
index 0a310d1..85840e1 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
@@ -87,7 +87,7 @@
         setting = new PackageSetting("name", "realName", new File("codePath"),
                 new File("resourcePath"), "legacyNativeLibraryPathString",
                 "primaryCpuAbiString", "secondaryCpuAbiString",
-                "cpuAbiOverrideString", 0, 0, 0, "parentPackageName", null, 0,
+                "cpuAbiOverrideString", 0, 0, 0, 0,
                 null, null);
         pri.populateUsers(new int[] {
                 1, 2, 3, 4, 5
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
index 1106be2..8329227 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -403,10 +403,6 @@
 
     private static final String PACKAGE_NAME = "com.android.bar";
     private static final String REAL_PACKAGE_NAME = "com.android.foo";
-    private static final String PARENT_PACKAGE_NAME = "com.android.bar.parent";
-    private static final String CHILD_PACKAGE_NAME_01 = "com.android.bar.child01";
-    private static final String CHILD_PACKAGE_NAME_02 = "com.android.bar.child02";
-    private static final String CHILD_PACKAGE_NAME_03 = "com.android.bar.child03";
     private static final File INITIAL_CODE_PATH =
             new File(InstrumentationRegistry.getContext().getFilesDir(), "com.android.bar-1");
     private static final File UPDATED_CODE_PATH =
@@ -416,10 +412,6 @@
 
     @Test
     public void testPackageStateCopy01() {
-        final List<String> childPackageNames = new ArrayList<>();
-        childPackageNames.add(CHILD_PACKAGE_NAME_01);
-        childPackageNames.add(CHILD_PACKAGE_NAME_02);
-        childPackageNames.add(CHILD_PACKAGE_NAME_03);
         final PackageSetting origPkgSetting01 = new PackageSetting(
                 PACKAGE_NAME,
                 REAL_PACKAGE_NAME,
@@ -432,8 +424,6 @@
                 INITIAL_VERSION_CODE,
                 ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_HAS_CODE,
                 ApplicationInfo.PRIVATE_FLAG_PRIVILEGED|ApplicationInfo.PRIVATE_FLAG_HIDDEN,
-                PARENT_PACKAGE_NAME,
-                childPackageNames,
                 0,
                 null /*usesStaticLibraries*/,
                 null /*usesStaticLibrariesVersions*/);
@@ -443,10 +433,6 @@
 
     @Test
     public void testPackageStateCopy02() {
-        final List<String> childPackageNames = new ArrayList<>();
-        childPackageNames.add(CHILD_PACKAGE_NAME_01);
-        childPackageNames.add(CHILD_PACKAGE_NAME_02);
-        childPackageNames.add(CHILD_PACKAGE_NAME_03);
         final PackageSetting origPkgSetting01 = new PackageSetting(
                 PACKAGE_NAME /*pkgName*/,
                 REAL_PACKAGE_NAME /*realPkgName*/,
@@ -459,8 +445,6 @@
                 INITIAL_VERSION_CODE,
                 ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_HAS_CODE,
                 ApplicationInfo.PRIVATE_FLAG_PRIVILEGED|ApplicationInfo.PRIVATE_FLAG_HIDDEN,
-                PARENT_PACKAGE_NAME,
-                childPackageNames,
                 0,
                 null /*usesStaticLibraries*/,
                 null /*usesStaticLibrariesVersions*/);
@@ -476,8 +460,6 @@
                 UPDATED_VERSION_CODE,
                 0 /*pkgFlags*/,
                 0 /*pkgPrivateFlags*/,
-                null /*parentPkgName*/,
-                null /*childPkgNames*/,
                 0,
                 null /*usesStaticLibraries*/,
                 null /*usesStaticLibrariesVersions*/);
@@ -505,7 +487,6 @@
                 "armeabi" /*secondaryCpuAbi*/,
                 0 /*pkgFlags*/,
                 0 /*pkgPrivateFlags*/,
-                null /*childPkgNames*/,
                 UserManagerService.getInstance(),
                 null /*usesStaticLibraries*/,
                 null /*usesStaticLibrariesVersions*/);
@@ -539,7 +520,6 @@
                 "armeabi" /*secondaryCpuAbi*/,
                 ApplicationInfo.FLAG_SYSTEM /*pkgFlags*/,
                 ApplicationInfo.PRIVATE_FLAG_PRIVILEGED /*pkgPrivateFlags*/,
-                null /*childPkgNames*/,
                 UserManagerService.getInstance(),
                 null /*usesStaticLibraries*/,
                 null /*usesStaticLibrariesVersions*/);
@@ -579,7 +559,6 @@
                     "armeabi" /*secondaryCpuAbi*/,
                     0 /*pkgFlags*/,
                     0 /*pkgPrivateFlags*/,
-                    null /*childPkgNames*/,
                     UserManagerService.getInstance(),
                     null /*usesStaticLibraries*/,
                     null /*usesStaticLibrariesVersions*/);
@@ -612,8 +591,6 @@
                 false /*allowInstall*/,
                 false /*instantApp*/,
                 false /*virtualPreload*/,
-                null /*parentPkgName*/,
-                null /*childPkgNames*/,
                 UserManagerService.getInstance(),
                 null /*usesStaticLibraries*/,
                 null /*usesStaticLibrariesVersions*/);
@@ -653,8 +630,6 @@
                 true /*allowInstall*/,
                 false /*instantApp*/,
                 false /*virtualPreload*/,
-                null /*parentPkgName*/,
-                null /*childPkgNames*/,
                 UserManagerService.getInstance(),
                 null /*usesStaticLibraries*/,
                 null /*usesStaticLibrariesVersions*/);
@@ -700,8 +675,6 @@
                 false /*allowInstall*/,
                 false /*instantApp*/,
                 false /*virtualPreload*/,
-                null /*parentPkgName*/,
-                null /*childPkgNames*/,
                 UserManagerService.getInstance(),
                 null /*usesStaticLibraries*/,
                 null /*usesStaticLibrariesVersions*/);
@@ -744,8 +717,6 @@
                 false /*allowInstall*/,
                 false /*instantApp*/,
                 false /*virtualPreload*/,
-                null /*parentPkgName*/,
-                null /*childPkgNames*/,
                 UserManagerService.getInstance(),
                 null /*usesStaticLibraries*/,
                 null /*usesStaticLibrariesVersions*/);
@@ -802,9 +773,6 @@
     private void verifySettingCopy(PackageSetting origPkgSetting, PackageSetting testPkgSetting) {
         assertThat(origPkgSetting, is(not(testPkgSetting)));
         assertThat(origPkgSetting.appId, is(testPkgSetting.appId));
-        // different but equal objects
-        assertNotSame(origPkgSetting.childPackageNames, testPkgSetting.childPackageNames);
-        assertThat(origPkgSetting.childPackageNames, is(testPkgSetting.childPackageNames));
         assertSame(origPkgSetting.codePath, testPkgSetting.codePath);
         assertThat(origPkgSetting.codePath, is(testPkgSetting.codePath));
         assertSame(origPkgSetting.codePathString, testPkgSetting.codePathString);
@@ -828,8 +796,6 @@
         // mOldCodePaths is _not_ copied
         // assertNotSame(origPkgSetting.mOldCodePaths, testPkgSetting.mOldCodePaths);
         // assertThat(origPkgSetting.mOldCodePaths, is(not(testPkgSetting.mOldCodePaths)));
-        assertSame(origPkgSetting.parentPackageName, testPkgSetting.parentPackageName);
-        assertThat(origPkgSetting.parentPackageName, is(testPkgSetting.parentPackageName));
         assertSame(origPkgSetting.pkg, testPkgSetting.pkg);
         // No equals() method for this object
         // assertThat(origPkgSetting.pkg, is(testPkgSetting.pkg));
@@ -881,8 +847,6 @@
                 INITIAL_VERSION_CODE,
                 pkgFlags,
                 0 /*privateFlags*/,
-                null /*parentPackageName*/,
-                null /*childPackageNames*/,
                 sharedUserId,
                 null /*usesStaticLibraries*/,
                 null /*usesStaticLibrariesVersions*/);
@@ -901,8 +865,6 @@
                 INITIAL_VERSION_CODE,
                 0,
                 0 /*privateFlags*/,
-                null /*parentPackageName*/,
-                null /*childPackageNames*/,
                 0,
                 null /*usesStaticLibraries*/,
                 null /*usesStaticLibrariesVersions*/);
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
index e33d8ca..162092b 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
@@ -15,35 +15,49 @@
  */
 package com.android.server.pm;
 
-import static android.content.res.Resources.ID_NULL;
-
+import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
 
-import android.content.Intent;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.ConfigurationInfo;
 import android.content.pm.FeatureGroupInfo;
 import android.content.pm.FeatureInfo;
-import android.content.pm.InstrumentationInfo;
+import android.content.pm.PackageInfo;
 import android.content.pm.PackageParser;
+import android.content.pm.PackageUserState;
 import android.content.pm.ProviderInfo;
 import android.content.pm.ServiceInfo;
 import android.content.pm.SharedLibraryInfo;
 import android.content.pm.Signature;
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.ComponentParseUtils;
+import android.content.pm.parsing.ComponentParseUtils.ParsedActivity;
+import android.content.pm.parsing.ComponentParseUtils.ParsedComponent;
+import android.content.pm.parsing.ComponentParseUtils.ParsedInstrumentation;
+import android.content.pm.parsing.ComponentParseUtils.ParsedIntentInfo;
+import android.content.pm.parsing.ComponentParseUtils.ParsedPermission;
+import android.content.pm.parsing.ComponentParseUtils.ParsedPermissionGroup;
+import android.content.pm.parsing.ComponentParseUtils.ParsedProvider;
+import android.content.pm.parsing.ComponentParseUtils.ParsedService;
+import android.content.pm.parsing.PackageImpl;
+import android.content.pm.parsing.PackageInfoUtils;
+import android.content.pm.parsing.ParsedPackage;
+import android.content.pm.parsing.ParsingPackage;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.platform.test.annotations.Presubmit;
-import android.util.ArrayMap;
 import android.util.ArraySet;
 
 import androidx.test.filters.MediumTest;
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.internal.util.ArrayUtils;
+
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -57,6 +71,7 @@
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
@@ -64,6 +79,9 @@
 @RunWith(AndroidJUnit4.class)
 @MediumTest
 public class PackageParserTest {
+    // TODO(b/135203078): Update this test with all fields and validate equality. Initial change
+    //  was just migrating to new interfaces. Consider adding actual equals() methods.
+
     @Rule
     public TemporaryFolder mTemporaryFolder = new TemporaryFolder();
 
@@ -79,12 +97,12 @@
     @Test
     public void testParse_noCache() throws Exception {
         PackageParser pp = new CachePackageNameParser();
-        PackageParser.Package pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */,
+        ParsedPackage pkg = pp.parseParsedPackage(FRAMEWORK, 0 /* parseFlags */,
                 false /* useCaches */);
         assertNotNull(pkg);
 
         pp.setCacheDir(mTmpDir);
-        pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */,
+        pkg = pp.parseParsedPackage(FRAMEWORK, 0 /* parseFlags */,
                 false /* useCaches */);
         assertNotNull(pkg);
 
@@ -99,27 +117,27 @@
 
         pp.setCacheDir(mTmpDir);
         // The first parse will write this package to the cache.
-        pp.parsePackage(FRAMEWORK, 0 /* parseFlags */, true /* useCaches */);
+        pp.parseParsedPackage(FRAMEWORK, 0 /* parseFlags */, true /* useCaches */);
 
         // Now attempt to parse the package again, should return the
         // cached result.
-        PackageParser.Package pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */,
+        ParsedPackage pkg = pp.parseParsedPackage(FRAMEWORK, 0 /* parseFlags */,
                 true /* useCaches */);
-        assertEquals("cache_android", pkg.packageName);
+        assertEquals("cache_android", pkg.getPackageName());
 
         // Try again, with useCaches == false, shouldn't return the parsed
         // result.
-        pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */, false /* useCaches */);
-        assertEquals("android", pkg.packageName);
+        pkg = pp.parseParsedPackage(FRAMEWORK, 0 /* parseFlags */, false /* useCaches */);
+        assertEquals("android", pkg.getPackageName());
 
         // We haven't set a cache directory here : the parse should still succeed,
         // just not using the cached results.
         pp = new CachePackageNameParser();
-        pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */, true /* useCaches */);
-        assertEquals("android", pkg.packageName);
+        pkg = pp.parseParsedPackage(FRAMEWORK, 0 /* parseFlags */, true /* useCaches */);
+        assertEquals("android", pkg.getPackageName());
 
-        pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */, false /* useCaches */);
-        assertEquals("android", pkg.packageName);
+        pkg = pp.parseParsedPackage(FRAMEWORK, 0 /* parseFlags */, false /* useCaches */);
+        assertEquals("android", pkg.getPackageName());
     }
 
     @Test
@@ -127,14 +145,14 @@
         PackageParser pp = new PackageParser();
         pp.setCacheDir(mTmpDir);
 
-        PackageParser.Package pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */,
-            true /* useCaches */);
+        ParsedPackage pkg = pp.parseParsedPackage(FRAMEWORK, 0 /* parseFlags */,
+                true /* useCaches */);
 
         Parcel p = Parcel.obtain();
         pkg.writeToParcel(p, 0 /* flags */);
 
         p.setDataPosition(0);
-        PackageParser.Package deserialized = new PackageParser.Package(p);
+        ParsedPackage deserialized = new PackageImpl(p);
 
         assertPackagesEqual(pkg, deserialized);
     }
@@ -143,154 +161,164 @@
     @SmallTest
     @Presubmit
     public void test_roundTripKnownFields() throws Exception {
-        PackageParser.Package pkg = new PackageParser.Package("foo");
+        ParsingPackage pkg = PackageImpl.forParsing("foo");
         setKnownFields(pkg);
 
         Parcel p = Parcel.obtain();
         pkg.writeToParcel(p, 0 /* flags */);
 
         p.setDataPosition(0);
-        PackageParser.Package deserialized = new PackageParser.Package(p);
+        ParsedPackage deserialized = new PackageImpl(p);
         assertAllFieldsExist(deserialized);
     }
 
     @Test
     public void test_stringInterning() throws Exception {
-        PackageParser.Package pkg = new PackageParser.Package("foo");
+        ParsingPackage pkg = PackageImpl.forParsing("foo");
         setKnownFields(pkg);
 
         Parcel p = Parcel.obtain();
         pkg.writeToParcel(p, 0 /* flags */);
 
         p.setDataPosition(0);
-        PackageParser.Package deserialized = new PackageParser.Package(p);
+        ParsingPackage deserialized = new PackageImpl(p);
 
         p.setDataPosition(0);
-        PackageParser.Package deserialized2 = new PackageParser.Package(p);
+        ParsingPackage deserialized2 = new PackageImpl(p);
 
-        assertSame(deserialized.packageName, deserialized2.packageName);
-        assertSame(deserialized.applicationInfo.permission,
-                deserialized2.applicationInfo.permission);
-        assertSame(deserialized.requestedPermissions.get(0),
-                deserialized2.requestedPermissions.get(0));
-        assertSame(deserialized.protectedBroadcasts.get(0),
-                deserialized2.protectedBroadcasts.get(0));
-        assertSame(deserialized.usesLibraries.get(0),
-                deserialized2.usesLibraries.get(0));
-        assertSame(deserialized.usesOptionalLibraries.get(0),
-                deserialized2.usesOptionalLibraries.get(0));
-        assertSame(deserialized.mVersionName, deserialized2.mVersionName);
-        assertSame(deserialized.mSharedUserId, deserialized2.mSharedUserId);
+        assertSame(deserialized.getPackageName(), deserialized2.getPackageName());
+        assertSame(deserialized.getPermission(),
+                deserialized2.getPermission());
+        assertSame(deserialized.getRequestedPermissions().get(0),
+                deserialized2.getRequestedPermissions().get(0));
+
+        List<String> protectedBroadcastsOne = new ArrayList<>(1);
+        protectedBroadcastsOne.addAll(deserialized.getProtectedBroadcasts());
+
+        List<String> protectedBroadcastsTwo = new ArrayList<>(1);
+        protectedBroadcastsTwo.addAll(deserialized2.getProtectedBroadcasts());
+
+        assertSame(protectedBroadcastsOne.get(0), protectedBroadcastsTwo.get(0));
+
+        assertSame(deserialized.getUsesLibraries().get(0),
+                deserialized2.getUsesLibraries().get(0));
+        assertSame(deserialized.getUsesOptionalLibraries().get(0),
+                deserialized2.getUsesOptionalLibraries().get(0));
+        assertSame(deserialized.getVersionName(), deserialized2.getVersionName());
+        assertSame(deserialized.getSharedUserId(), deserialized2.getSharedUserId());
     }
 
-
     /**
      * A trivial subclass of package parser that only caches the package name, and throws away
      * all other information.
      */
     public static class CachePackageNameParser extends PackageParser {
         @Override
-        public byte[] toCacheEntry(Package pkg) {
-            return ("cache_" + pkg.packageName).getBytes(StandardCharsets.UTF_8);
+        public byte[] toCacheEntry(ParsedPackage pkg) {
+            return ("cache_" + pkg.getPackageName()).getBytes(StandardCharsets.UTF_8);
         }
 
         @Override
-        public Package fromCacheEntry(byte[] cacheEntry) {
-            return new Package(new String(cacheEntry, StandardCharsets.UTF_8));
+        public ParsedPackage fromCacheEntry(byte[] cacheEntry) {
+            return PackageImpl.forParsing(new String(cacheEntry, StandardCharsets.UTF_8))
+                    .hideAsParsed();
         }
     }
 
     // NOTE: The equality assertions below are based on code autogenerated by IntelliJ.
 
-    public static void assertPackagesEqual(PackageParser.Package a, PackageParser.Package b) {
-        assertEquals(a.baseRevisionCode, b.baseRevisionCode);
-        assertEquals(a.baseHardwareAccelerated, b.baseHardwareAccelerated);
-        assertEquals(a.mVersionCode, b.mVersionCode);
-        assertEquals(a.mSharedUserLabel, b.mSharedUserLabel);
-        assertEquals(a.mPreferredOrder, b.mPreferredOrder);
-        assertEquals(a.installLocation, b.installLocation);
-        assertEquals(a.coreApp, b.coreApp);
-        assertEquals(a.mRequiredForAllUsers, b.mRequiredForAllUsers);
-        assertEquals(a.mCompileSdkVersion, b.mCompileSdkVersion);
-        assertEquals(a.mCompileSdkVersionCodename, b.mCompileSdkVersionCodename);
-        assertEquals(a.use32bitAbi, b.use32bitAbi);
-        assertEquals(a.packageName, b.packageName);
-        assertTrue(Arrays.equals(a.splitNames, b.splitNames));
-        assertEquals(a.volumeUuid, b.volumeUuid);
-        assertEquals(a.codePath, b.codePath);
-        assertEquals(a.baseCodePath, b.baseCodePath);
-        assertTrue(Arrays.equals(a.splitCodePaths, b.splitCodePaths));
-        assertTrue(Arrays.equals(a.splitRevisionCodes, b.splitRevisionCodes));
-        assertTrue(Arrays.equals(a.splitFlags, b.splitFlags));
-        assertTrue(Arrays.equals(a.splitPrivateFlags, b.splitPrivateFlags));
-        assertApplicationInfoEqual(a.applicationInfo, b.applicationInfo);
+    public static void assertPackagesEqual(AndroidPackage a, AndroidPackage b) {
+        assertEquals(a.getBaseRevisionCode(), b.getBaseRevisionCode());
+        assertEquals(a.isBaseHardwareAccelerated(), b.isBaseHardwareAccelerated());
+        assertEquals(a.getVersionCode(), b.getVersionCode());
+        assertEquals(a.getSharedUserLabel(), b.getSharedUserLabel());
+        assertEquals(a.getPreferredOrder(), b.getPreferredOrder());
+        assertEquals(a.getInstallLocation(), b.getInstallLocation());
+        assertEquals(a.isCoreApp(), b.isCoreApp());
+        assertEquals(a.isRequiredForAllUsers(), b.isRequiredForAllUsers());
+        assertEquals(a.getCompileSdkVersion(), b.getCompileSdkVersion());
+        assertEquals(a.getCompileSdkVersionCodeName(), b.getCompileSdkVersionCodeName());
+        assertEquals(a.isUse32BitAbi(), b.isUse32BitAbi());
+        assertEquals(a.getPackageName(), b.getPackageName());
+        assertArrayEquals(a.getSplitNames(), b.getSplitNames());
+        assertEquals(a.getVolumeUuid(), b.getVolumeUuid());
+        assertEquals(a.getCodePath(), b.getCodePath());
+        assertEquals(a.getBaseCodePath(), b.getBaseCodePath());
+        assertArrayEquals(a.getSplitCodePaths(), b.getSplitCodePaths());
+        assertArrayEquals(a.getSplitRevisionCodes(), b.getSplitRevisionCodes());
+        assertArrayEquals(a.getSplitFlags(), b.getSplitFlags());
 
-        assertEquals(a.permissions.size(), b.permissions.size());
-        for (int i = 0; i < a.permissions.size(); ++i) {
-            assertPermissionsEqual(a.permissions.get(i), b.permissions.get(i));
-            assertSame(a.permissions.get(i).owner, a);
-            assertSame(b.permissions.get(i).owner, b);
+        PackageInfo aInfo = PackageInfoUtils.generate(a, new int[]{}, 0, 0, 0,
+                Collections.emptySet(), new PackageUserState(), 0);
+        PackageInfo bInfo = PackageInfoUtils.generate(b, new int[]{}, 0, 0, 0,
+                Collections.emptySet(), new PackageUserState(), 0);
+        assertApplicationInfoEqual(aInfo.applicationInfo, bInfo.applicationInfo);
+
+        assertEquals(ArrayUtils.size(a.getPermissions()), ArrayUtils.size(b.getPermissions()));
+        for (int i = 0; i < ArrayUtils.size(a.getPermissions()); ++i) {
+            assertPermissionsEqual(a.getPermissions().get(i), b.getPermissions().get(i));
         }
 
-        assertEquals(a.permissionGroups.size(), b.permissionGroups.size());
-        for (int i = 0; i < a.permissionGroups.size(); ++i) {
-            assertPermissionGroupsEqual(a.permissionGroups.get(i), b.permissionGroups.get(i));
+        assertEquals(ArrayUtils.size(a.getPermissionGroups()),
+                ArrayUtils.size(b.getPermissionGroups()));
+        for (int i = 0; i < a.getPermissionGroups().size(); ++i) {
+            assertPermissionGroupsEqual(a.getPermissionGroups().get(i),
+                    b.getPermissionGroups().get(i));
         }
 
-        assertEquals(a.activities.size(), b.activities.size());
-        for (int i = 0; i < a.activities.size(); ++i) {
-            assertActivitiesEqual(a.activities.get(i), b.activities.get(i));
+        assertEquals(ArrayUtils.size(a.getActivities()), ArrayUtils.size(b.getActivities()));
+        for (int i = 0; i < ArrayUtils.size(a.getActivities()); ++i) {
+            assertActivitiesEqual(a, a.getActivities().get(i), b, b.getActivities().get(i));
         }
 
-        assertEquals(a.receivers.size(), b.receivers.size());
-        for (int i = 0; i < a.receivers.size(); ++i) {
-            assertActivitiesEqual(a.receivers.get(i), b.receivers.get(i));
+        assertEquals(ArrayUtils.size(a.getReceivers()), ArrayUtils.size(b.getReceivers()));
+        for (int i = 0; i < ArrayUtils.size(a.getReceivers()); ++i) {
+            assertActivitiesEqual(a, a.getReceivers().get(i), b, b.getReceivers().get(i));
         }
 
-        assertEquals(a.providers.size(), b.providers.size());
-        for (int i = 0; i < a.providers.size(); ++i) {
-            assertProvidersEqual(a.providers.get(i), b.providers.get(i));
+        assertEquals(ArrayUtils.size(a.getProviders()), ArrayUtils.size(b.getProviders()));
+        for (int i = 0; i < ArrayUtils.size(a.getProviders()); ++i) {
+            assertProvidersEqual(a, a.getProviders().get(i), b, b.getProviders().get(i));
         }
 
-        assertEquals(a.services.size(), b.services.size());
-        for (int i = 0; i < a.services.size(); ++i) {
-            assertServicesEqual(a.services.get(i), b.services.get(i));
+        assertEquals(ArrayUtils.size(a.getServices()), ArrayUtils.size(b.getServices()));
+        for (int i = 0; i < ArrayUtils.size(a.getServices()); ++i) {
+            assertServicesEqual(a, a.getServices().get(i), b, b.getServices().get(i));
         }
 
-        assertEquals(a.instrumentation.size(), b.instrumentation.size());
-        for (int i = 0; i < a.instrumentation.size(); ++i) {
-            assertInstrumentationEqual(a.instrumentation.get(i), b.instrumentation.get(i));
+        assertEquals(ArrayUtils.size(a.getInstrumentations()),
+                ArrayUtils.size(b.getInstrumentations()));
+        for (int i = 0; i < ArrayUtils.size(a.getInstrumentations()); ++i) {
+            assertInstrumentationEqual(a.getInstrumentations().get(i),
+                    b.getInstrumentations().get(i));
         }
 
-        assertEquals(a.requestedPermissions, b.requestedPermissions);
-        assertEquals(a.protectedBroadcasts, b.protectedBroadcasts);
-        assertEquals(a.parentPackage, b.parentPackage);
-        assertEquals(a.childPackages, b.childPackages);
-        assertEquals(a.libraryNames, b.libraryNames);
-        assertEquals(a.usesLibraries, b.usesLibraries);
-        assertEquals(a.usesOptionalLibraries, b.usesOptionalLibraries);
-        assertTrue(Arrays.equals(a.usesLibraryFiles, b.usesLibraryFiles));
-        assertEquals(a.mOriginalPackages, b.mOriginalPackages);
-        assertEquals(a.mRealPackage, b.mRealPackage);
-        assertEquals(a.mAdoptPermissions, b.mAdoptPermissions);
-        assertBundleApproximateEquals(a.mAppMetaData, b.mAppMetaData);
-        assertEquals(a.mVersionName, b.mVersionName);
-        assertEquals(a.mSharedUserId, b.mSharedUserId);
-        assertTrue(Arrays.equals(a.mSigningDetails.signatures, b.mSigningDetails.signatures));
-        assertTrue(Arrays.equals(a.mLastPackageUsageTimeInMills, b.mLastPackageUsageTimeInMills));
-        assertEquals(a.mExtras, b.mExtras);
-        assertEquals(a.mRestrictedAccountType, b.mRestrictedAccountType);
-        assertEquals(a.mRequiredAccountType, b.mRequiredAccountType);
-        assertEquals(a.mOverlayTarget, b.mOverlayTarget);
-        assertEquals(a.mOverlayTargetName, b.mOverlayTargetName);
-        assertEquals(a.mOverlayCategory, b.mOverlayCategory);
-        assertEquals(a.mOverlayPriority, b.mOverlayPriority);
-        assertEquals(a.mOverlayIsStatic, b.mOverlayIsStatic);
-        assertEquals(a.mSigningDetails.publicKeys, b.mSigningDetails.publicKeys);
-        assertEquals(a.mUpgradeKeySets, b.mUpgradeKeySets);
-        assertEquals(a.mKeySetMapping, b.mKeySetMapping);
-        assertEquals(a.cpuAbiOverride, b.cpuAbiOverride);
-        assertTrue(Arrays.equals(a.restrictUpdateHash, b.restrictUpdateHash));
+        assertEquals(a.getRequestedPermissions(), b.getRequestedPermissions());
+        assertEquals(a.getProtectedBroadcasts(), b.getProtectedBroadcasts());
+        assertEquals(a.getLibraryNames(), b.getLibraryNames());
+        assertEquals(a.getUsesLibraries(), b.getUsesLibraries());
+        assertEquals(a.getUsesOptionalLibraries(), b.getUsesOptionalLibraries());
+        assertArrayEquals(a.getUsesLibraryFiles(), b.getUsesLibraryFiles());
+        assertEquals(a.getOriginalPackages(), b.getOriginalPackages());
+        assertEquals(a.getRealPackage(), b.getRealPackage());
+        assertEquals(a.getAdoptPermissions(), b.getAdoptPermissions());
+        assertBundleApproximateEquals(a.getAppMetaData(), b.getAppMetaData());
+        assertEquals(a.getVersionName(), b.getVersionName());
+        assertEquals(a.getSharedUserId(), b.getSharedUserId());
+        assertArrayEquals(a.getSigningDetails().signatures, b.getSigningDetails().signatures);
+        assertArrayEquals(a.getLastPackageUsageTimeInMills(), b.getLastPackageUsageTimeInMills());
+        assertEquals(a.getRestrictedAccountType(), b.getRestrictedAccountType());
+        assertEquals(a.getRequiredAccountType(), b.getRequiredAccountType());
+        assertEquals(a.getOverlayTarget(), b.getOverlayTarget());
+        assertEquals(a.getOverlayTargetName(), b.getOverlayTargetName());
+        assertEquals(a.getOverlayCategory(), b.getOverlayCategory());
+        assertEquals(a.getOverlayPriority(), b.getOverlayPriority());
+        assertEquals(a.isOverlayIsStatic(), b.isOverlayIsStatic());
+        assertEquals(a.getSigningDetails().publicKeys, b.getSigningDetails().publicKeys);
+        assertEquals(a.getUpgradeKeySets(), b.getUpgradeKeySets());
+        assertEquals(a.getKeySetMapping(), b.getKeySetMapping());
+        assertEquals(a.getCpuAbiOverride(), b.getCpuAbiOverride());
+        assertArrayEquals(a.getRestrictUpdateHash(), b.getRestrictUpdateHash());
     }
 
     private static void assertBundleApproximateEquals(Bundle a, Bundle b) {
@@ -305,10 +333,10 @@
         assertEquals(a.toString(), b.toString());
     }
 
-    private static void assertComponentsEqual(PackageParser.Component<?> a,
-                                              PackageParser.Component<?> b) {
+    private static void assertComponentsEqual(ParsedComponent<?> a,
+            ParsedComponent<?> b) {
         assertEquals(a.className, b.className);
-        assertBundleApproximateEquals(a.metaData, b.metaData);
+        assertBundleApproximateEquals(a.getMetaData(), b.getMetaData());
         assertEquals(a.getComponentName(), b.getComponentName());
 
         if (a.intents != null && b.intents != null) {
@@ -318,80 +346,104 @@
         }
 
         for (int i = 0; i < a.intents.size(); ++i) {
-            PackageParser.IntentInfo aIntent = a.intents.get(i);
-            PackageParser.IntentInfo bIntent = b.intents.get(i);
+            ParsedIntentInfo aIntent = a.intents.get(i);
+            ParsedIntentInfo bIntent = b.intents.get(i);
 
             assertEquals(aIntent.hasDefault, bIntent.hasDefault);
             assertEquals(aIntent.labelRes, bIntent.labelRes);
             assertEquals(aIntent.nonLocalizedLabel, bIntent.nonLocalizedLabel);
             assertEquals(aIntent.icon, bIntent.icon);
-            assertEquals(aIntent.logo, bIntent.logo);
-            assertEquals(aIntent.banner, bIntent.banner);
-            assertEquals(aIntent.preferred, bIntent.preferred);
         }
     }
 
-    private static void assertPermissionsEqual(PackageParser.Permission a,
-                                               PackageParser.Permission b) {
+    private static void assertPermissionsEqual(ParsedPermission a,
+            ParsedPermission b) {
         assertComponentsEqual(a, b);
         assertEquals(a.tree, b.tree);
 
         // Verify basic flags in PermissionInfo to make sure they're consistent. We don't perform
         // a full structural equality here because the code that serializes them isn't parser
         // specific and is tested elsewhere.
-        assertEquals(a.info.protectionLevel, b.info.protectionLevel);
-        assertEquals(a.info.group, b.info.group);
-        assertEquals(a.info.flags, b.info.flags);
+        assertEquals(a.getProtection(), b.getProtection());
+        assertEquals(a.getGroup(), b.getGroup());
+        assertEquals(a.flags, b.flags);
 
-        if (a.group != null && b.group != null) {
-            assertPermissionGroupsEqual(a.group, b.group);
-        } else if (a.group != null || b.group != null) {
+        if (a.parsedPermissionGroup != null && b.parsedPermissionGroup != null) {
+            assertPermissionGroupsEqual(a.parsedPermissionGroup, b.parsedPermissionGroup);
+        } else if (a.parsedPermissionGroup != null || b.parsedPermissionGroup != null) {
             throw new AssertionError();
         }
     }
 
-    private static void assertInstrumentationEqual(PackageParser.Instrumentation a,
-                                                   PackageParser.Instrumentation b) {
+    private static void assertInstrumentationEqual(ParsedInstrumentation a,
+            ParsedInstrumentation b) {
         assertComponentsEqual(a, b);
 
         // Sanity check for InstrumentationInfo.
-        assertEquals(a.info.targetPackage, b.info.targetPackage);
-        assertEquals(a.info.targetProcesses, b.info.targetProcesses);
-        assertEquals(a.info.sourceDir, b.info.sourceDir);
-        assertEquals(a.info.publicSourceDir, b.info.publicSourceDir);
+        assertEquals(a.getTargetPackage(), b.getTargetPackage());
+        assertEquals(a.getTargetProcesses(), b.getTargetProcesses());
+        assertEquals(a.sourceDir, b.sourceDir);
+        assertEquals(a.publicSourceDir, b.publicSourceDir);
     }
 
-    private static void assertServicesEqual(PackageParser.Service a, PackageParser.Service b) {
+    private static void assertServicesEqual(
+            AndroidPackage aPkg,
+            ParsedService a,
+            AndroidPackage bPkg,
+            ParsedService b
+    ) {
         assertComponentsEqual(a, b);
 
         // Sanity check for ServiceInfo.
-        assertApplicationInfoEqual(a.info.applicationInfo, b.info.applicationInfo);
-        assertEquals(a.info.name, b.info.name);
+        ServiceInfo aInfo = PackageInfoUtils.generateServiceInfo(aPkg, a, 0, new PackageUserState(),
+                0);
+        ServiceInfo bInfo = PackageInfoUtils.generateServiceInfo(bPkg, b, 0, new PackageUserState(),
+                0);
+        assertApplicationInfoEqual(aInfo.applicationInfo, bInfo.applicationInfo);
+        assertEquals(a.getName(), b.getName());
     }
 
-    private static void assertProvidersEqual(PackageParser.Provider a, PackageParser.Provider b) {
+    private static void assertProvidersEqual(
+            AndroidPackage aPkg,
+            ParsedProvider a,
+            AndroidPackage bPkg,
+            ParsedProvider b
+    ) {
         assertComponentsEqual(a, b);
 
         // Sanity check for ProviderInfo
-        assertApplicationInfoEqual(a.info.applicationInfo, b.info.applicationInfo);
-        assertEquals(a.info.name, b.info.name);
+        ProviderInfo aInfo = PackageInfoUtils.generateProviderInfo(aPkg, a, 0,
+                new PackageUserState(), 0);
+        ProviderInfo bInfo = PackageInfoUtils.generateProviderInfo(bPkg, b, 0,
+                new PackageUserState(), 0);
+        assertApplicationInfoEqual(aInfo.applicationInfo, bInfo.applicationInfo);
+        assertEquals(a.getName(), b.getName());
     }
 
-    private static void assertActivitiesEqual(PackageParser.Activity a, PackageParser.Activity b) {
+    private static void assertActivitiesEqual(
+            AndroidPackage aPkg,
+            ParsedActivity a,
+            AndroidPackage bPkg,
+            ParsedActivity b
+    ) {
         assertComponentsEqual(a, b);
 
         // Sanity check for ActivityInfo.
-        assertApplicationInfoEqual(a.info.applicationInfo, b.info.applicationInfo);
-        assertEquals(a.info.name, b.info.name);
+        ActivityInfo aInfo = PackageInfoUtils.generateActivityInfo(aPkg, a, 0,
+                new PackageUserState(), 0);
+        ActivityInfo bInfo = PackageInfoUtils.generateActivityInfo(bPkg, b, 0,
+                new PackageUserState(), 0);
+        assertApplicationInfoEqual(aInfo.applicationInfo, bInfo.applicationInfo);
+        assertEquals(a.getName(), b.getName());
     }
 
-    private static void assertPermissionGroupsEqual(PackageParser.PermissionGroup a,
-                                                    PackageParser.PermissionGroup b) {
+    private static void assertPermissionGroupsEqual(ParsedPermissionGroup a,
+            ParsedPermissionGroup b) {
         assertComponentsEqual(a, b);
 
         // Sanity check for PermissionGroupInfo.
-        assertEquals(a.info.name, b.info.name);
-        assertEquals(a.info.descriptionRes, b.info.descriptionRes);
+        assertEquals(a.getName(), b.getName());
+        assertEquals(a.descriptionRes, b.descriptionRes);
     }
 
     private static void assertApplicationInfoEqual(ApplicationInfo a, ApplicationInfo that) {
@@ -424,11 +476,11 @@
         assertEquals(a.scanPublicSourceDir, that.scanPublicSourceDir);
         assertEquals(a.sourceDir, that.sourceDir);
         assertEquals(a.publicSourceDir, that.publicSourceDir);
-        assertTrue(Arrays.equals(a.splitSourceDirs, that.splitSourceDirs));
-        assertTrue(Arrays.equals(a.splitPublicSourceDirs, that.splitPublicSourceDirs));
-        assertTrue(Arrays.equals(a.resourceDirs, that.resourceDirs));
+        assertArrayEquals(a.splitSourceDirs, that.splitSourceDirs);
+        assertArrayEquals(a.splitPublicSourceDirs, that.splitPublicSourceDirs);
+        assertArrayEquals(a.resourceDirs, that.resourceDirs);
         assertEquals(a.seInfo, that.seInfo);
-        assertTrue(Arrays.equals(a.sharedLibraryFiles, that.sharedLibraryFiles));
+        assertArrayEquals(a.sharedLibraryFiles, that.sharedLibraryFiles);
         assertEquals(a.dataDir, that.dataDir);
         assertEquals(a.deviceProtectedDataDir, that.deviceProtectedDataDir);
         assertEquals(a.credentialProtectedDataDir, that.credentialProtectedDataDir);
@@ -439,132 +491,93 @@
         assertEquals(a.secondaryCpuAbi, that.secondaryCpuAbi);
     }
 
-    public static void setKnownFields(PackageParser.Package pkg) {
-        pkg.baseRevisionCode = 100;
-        pkg.baseHardwareAccelerated = true;
-        pkg.mVersionCode = 100;
-        pkg.mSharedUserLabel = 100;
-        pkg.mPreferredOrder = 100;
-        pkg.installLocation = 100;
-        pkg.coreApp = true;
-        pkg.mRequiredForAllUsers = true;
-        pkg.use32bitAbi = true;
-        pkg.packageName = "foo";
-        pkg.splitNames = new String[] { "foo2" };
-        pkg.volumeUuid = "foo3";
-        pkg.codePath = "foo4";
-        pkg.baseCodePath = "foo5";
-        pkg.splitCodePaths = new String[] { "foo6" };
-        pkg.splitRevisionCodes = new int[] { 100 };
-        pkg.splitFlags = new int[] { 100 };
-        pkg.splitPrivateFlags = new int[] { 100 };
-        pkg.applicationInfo = new ApplicationInfo();
+    public static void setKnownFields(ParsingPackage pkg) {
+        Bundle bundle = new Bundle();
+        bundle.putString("key", "value");
 
-        pkg.permissions.add(new PackageParser.Permission(pkg, (String) null));
-        pkg.permissionGroups.add(new PackageParser.PermissionGroup(pkg, ID_NULL, ID_NULL, ID_NULL));
+        ParsedPermission permission = new ParsedPermission();
+        permission.parsedPermissionGroup = new ParsedPermissionGroup();
 
-        final PackageParser.ParseComponentArgs dummy = new PackageParser.ParseComponentArgs(
-                pkg, new String[1], 0, 0, 0, 0, 0, 0, null, 0, 0, 0);
-
-        pkg.activities.add(new PackageParser.Activity(dummy, new ActivityInfo()));
-        pkg.receivers.add(new PackageParser.Activity(dummy, new ActivityInfo()));
-        pkg.providers.add(new PackageParser.Provider(dummy, new ProviderInfo()));
-        pkg.services.add(new PackageParser.Service(dummy, new ServiceInfo()));
-        pkg.instrumentation.add(new PackageParser.Instrumentation(dummy, new InstrumentationInfo()));
-        pkg.requestedPermissions.add("foo7");
-        pkg.implicitPermissions.add("foo25");
-
-        pkg.protectedBroadcasts = new ArrayList<>();
-        pkg.protectedBroadcasts.add("foo8");
-
-        pkg.parentPackage = new PackageParser.Package("foo9");
-
-        pkg.childPackages = new ArrayList<>();
-        pkg.childPackages.add(new PackageParser.Package("bar"));
-
-        pkg.staticSharedLibName = "foo23";
-        pkg.staticSharedLibVersion = 100;
-        pkg.usesStaticLibraries = new ArrayList<>();
-        pkg.usesStaticLibraries.add("foo23");
-        pkg.usesStaticLibrariesCertDigests = new String[1][];
-        pkg.usesStaticLibrariesCertDigests[0] = new String[] { "digest" };
-        pkg.usesStaticLibrariesVersions = new long[] { 100 };
-
-        pkg.libraryNames = new ArrayList<>();
-        pkg.libraryNames.add("foo10");
-
-        pkg.usesLibraries = new ArrayList<>();
-        pkg.usesLibraries.add("foo11");
-
-        pkg.usesOptionalLibraries = new ArrayList<>();
-        pkg.usesOptionalLibraries.add("foo12");
-
-        pkg.usesLibraryFiles = new String[] { "foo13"};
-
-        pkg.usesLibraryInfos = new ArrayList<>();
-        pkg.usesLibraryInfos.add(
-                new SharedLibraryInfo(null, null, null, null, 0L, 0, null, null, null));
-
-        pkg.mOriginalPackages = new ArrayList<>();
-        pkg.mOriginalPackages.add("foo14");
-
-        pkg.mRealPackage = "foo15";
-
-        pkg.mAdoptPermissions = new ArrayList<>();
-        pkg.mAdoptPermissions.add("foo16");
-
-        pkg.mAppMetaData = new Bundle();
-        pkg.mVersionName = "foo17";
-        pkg.mSharedUserId = "foo18";
-        pkg.mSigningDetails =
-                new PackageParser.SigningDetails(
-                        new Signature[] { new Signature(new byte[16]) },
-                        2,
-                        new ArraySet<>(),
-                        null);
-        pkg.mExtras = new Bundle();
-        pkg.mRestrictedAccountType = "foo19";
-        pkg.mRequiredAccountType = "foo20";
-        pkg.mOverlayTarget = "foo21";
-        pkg.mOverlayPriority = 100;
-        pkg.mUpgradeKeySets = new ArraySet<>();
-        pkg.mKeySetMapping = new ArrayMap<>();
-        pkg.cpuAbiOverride = "foo22";
-        pkg.restrictUpdateHash = new byte[16];
-
-        pkg.preferredActivityFilters = new ArrayList<>();
-        pkg.preferredActivityFilters.add(new PackageParser.ActivityIntentInfo(
-                new PackageParser.Activity(dummy, new ActivityInfo())));
-
-        pkg.configPreferences = new ArrayList<>();
-        pkg.configPreferences.add(new ConfigurationInfo());
-
-        pkg.reqFeatures = new ArrayList<>();
-        pkg.reqFeatures.add(new FeatureInfo());
-
-        pkg.featureGroups = new ArrayList<>();
-        pkg.featureGroups.add(new FeatureGroupInfo());
-
-        pkg.mCompileSdkVersionCodename = "foo23";
-        pkg.mCompileSdkVersion = 100;
-        pkg.mVersionCodeMajor = 100;
-
-        pkg.mOverlayCategory = "foo24";
-        pkg.mOverlayIsStatic = true;
-        pkg.mOverlayTargetName = "foo26";
-
-        pkg.baseHardwareAccelerated = true;
-        pkg.coreApp = true;
-        pkg.mRequiredForAllUsers = true;
-        pkg.visibleToInstantApps = true;
-        pkg.use32bitAbi = true;
-        pkg.mForceQueryable = true;
-        pkg.mQueriesPackages = new ArrayList<>(Arrays.asList("foo27"));
-        pkg.mQueriesIntents = new ArrayList<>(Arrays.asList(new Intent("foo28")));
+        pkg.setBaseRevisionCode(100)
+                .setBaseHardwareAccelerated(true)
+                .setSharedUserLabel(100)
+                .setPreferredOrder(100)
+                .setInstallLocation(100)
+                .setRequiredForAllUsers(true)
+                .asSplit(
+                        new String[]{"foo2"},
+                        new String[]{"foo6"},
+                        new int[]{100},
+                        null
+                )
+                .setUse32BitAbi(true)
+                .setVolumeUuid("foo3")
+                .setCodePath("foo4")
+                .addPermission(permission)
+                .addPermissionGroup(new ParsedPermissionGroup())
+                .addActivity(new ParsedActivity())
+                .addReceiver(new ParsedActivity())
+                .addProvider(new ParsedProvider())
+                .addService(new ParsedService())
+                .addInstrumentation(new ParsedInstrumentation())
+                .addRequestedPermission("foo7")
+                .addImplicitPermission("foo25")
+                .addProtectedBroadcast("foo8")
+                .setStaticSharedLibName("foo23")
+                .setStaticSharedLibVersion(100)
+                .addUsesStaticLibrary("foo23")
+                .addUsesStaticLibraryCertDigests(new String[]{"digest"})
+                .addUsesStaticLibraryVersion(100)
+                .addLibraryName("foo10")
+                .addUsesLibrary("foo11")
+                .addUsesOptionalLibrary("foo12")
+                .addOriginalPackage("foo14")
+                .setRealPackage("foo15")
+                .addAdoptPermission("foo16")
+                .setAppMetaData(bundle)
+                .setVersionName("foo17")
+                .setSharedUserId("foo18")
+                .setSigningDetails(
+                        new PackageParser.SigningDetails(
+                                new Signature[]{new Signature(new byte[16])},
+                                2,
+                                new ArraySet<>(),
+                                null)
+                )
+                .setRestrictedAccountType("foo19")
+                .setRequiredAccountType("foo20")
+                .setOverlayTarget("foo21")
+                .setOverlayPriority(100)
+                .setUpgradeKeySets(new ArraySet<>())
+                .addPreferredActivityFilter(
+                        new ComponentParseUtils.ParsedActivityIntentInfo("foo", "className"))
+                .addConfigPreference(new ConfigurationInfo())
+                .addReqFeature(new FeatureInfo())
+                .addFeatureGroup(new FeatureGroupInfo())
+                .setCompileSdkVersionCodename("foo23")
+                .setCompileSdkVersion(100)
+                .setOverlayCategory("foo24")
+                .setOverlayIsStatic(true)
+                .setOverlayTargetName("foo26")
+                .setVisibleToInstantApps(true)
+                .setSplitHasCode(0, true)
+                .hideAsParsed()
+                .setBaseCodePath("foo5")
+                .setVersionCode(100)
+                .setCpuAbiOverride("foo22")
+                .setRestrictUpdateHash(new byte[16])
+                .setVersionCodeMajor(100)
+                .setCoreApp(true)
+                .hideAsFinal()
+                .mutate()
+                .setUsesLibraryInfos(Arrays.asList(
+                        new SharedLibraryInfo(null, null, null, null, 0L, 0, null, null, null)
+                ))
+                .setUsesLibraryFiles(new String[]{"foo13"});
     }
 
-    private static void assertAllFieldsExist(PackageParser.Package pkg) throws Exception {
-        Field[] fields = PackageParser.Package.class.getDeclaredFields();
+    private static void assertAllFieldsExist(ParsedPackage pkg) throws Exception {
+        Field[] fields = ParsedPackage.class.getDeclaredFields();
 
         Set<String> nonSerializedFields = new HashSet<>();
         nonSerializedFields.add("mExtras");
@@ -601,7 +614,7 @@
             } else if (fieldType == boolean.class) {
                 // boolean fields: Check that they're set to true.
                 boolean value = (boolean) f.get(pkg);
-                assertEquals("Bad value for field: " + f, true, value);
+                assertTrue("Bad value for field: " + f, value);
             } else {
                 // All other fields: Check that they're set.
                 Object o = f.get(pkg);
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java b/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java
index 8d476f6..374e13a 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java
@@ -16,12 +16,11 @@
 
 package com.android.server.pm;
 
-import android.content.pm.PackageParser;
 import android.content.pm.PackageUserState;
+import android.content.pm.parsing.AndroidPackage;
 import android.util.SparseArray;
 
 import java.io.File;
-import java.util.List;
 
 class PackageSettingBuilder {
     private String mName;
@@ -35,8 +34,6 @@
     private long mPVersionCode;
     private int mPkgFlags;
     private int mPrivateFlags;
-    private String mParentPackageName;
-    private List<String> mChildPackageNames;
     private int mSharedUserId;
     private String[] mUsesStaticLibraries;
     private long[] mUsesStaticLibrariesVersions;
@@ -45,7 +42,7 @@
     private PackageParser.Package mPkg;
     private int mAppId;
 
-    public PackageSettingBuilder setPackage(PackageParser.Package pkg) {
+    public PackageSettingBuilder setPackage(AndroidPackage pkg) {
         this.mPkg = pkg;
         return this;
     }
@@ -111,16 +108,6 @@
         return this;
     }
 
-    public PackageSettingBuilder setParentPackageName(String parentPackageName) {
-        this.mParentPackageName = parentPackageName;
-        return this;
-    }
-
-    public PackageSettingBuilder setChildPackageNames(List<String> childPackageNames) {
-        this.mChildPackageNames = childPackageNames;
-        return this;
-    }
-
     public PackageSettingBuilder setSharedUserId(int sharedUserId) {
         this.mSharedUserId = sharedUserId;
         return this;
@@ -154,9 +141,8 @@
         final PackageSetting packageSetting = new PackageSetting(mName, mRealName,
                 new File(mCodePath), new File(mResourcePath),
                 mLegacyNativeLibraryPathString, mPrimaryCpuAbiString, mSecondaryCpuAbiString,
-                mCpuAbiOverrideString, mPVersionCode, mPkgFlags, mPrivateFlags, mParentPackageName,
-                mChildPackageNames, mSharedUserId, mUsesStaticLibraries,
-                mUsesStaticLibrariesVersions);
+                mCpuAbiOverrideString, mPVersionCode, mPkgFlags, mPrivateFlags, mSharedUserId,
+                mUsesStaticLibraries, mUsesStaticLibrariesVersions);
         packageSetting.pkg = mPkg;
         packageSetting.appId = mAppId;
         packageSetting.volumeUuid = this.mVolumeUuid;
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageSignaturesTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageSignaturesTest.java
index d3a77d3..04e769d 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageSignaturesTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageSignaturesTest.java
@@ -16,8 +16,8 @@
 package com.android.server.pm;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
@@ -467,8 +467,7 @@
         File appPath = new File("/data/app/app");
         PackageSetting result = new PackageSetting("test.app", null, appPath, appPath,
                 "/data/app/app", null, null, null,
-                1, 940097092, 0, null,
-                null, 0 /*userId*/, null, null);
+                1, 940097092, 0, 0 /*userId*/, null, null);
         return result;
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/pm/ParallelPackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/ParallelPackageParserTest.java
index 41489dc..a0efc8a 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ParallelPackageParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ParallelPackageParserTest.java
@@ -17,6 +17,7 @@
 package com.android.server.pm;
 
 import android.content.pm.PackageParser;
+import android.content.pm.parsing.ParsedPackage;
 import android.util.Log;
 
 import androidx.test.runner.AndroidJUnit4;
@@ -74,7 +75,7 @@
         }
 
         @Override
-        protected PackageParser.Package parsePackage(PackageParser packageParser, File scanFile,
+        protected ParsedPackage parsePackage(PackageParser packageParser, File scanFile,
                 int parseFlags) throws PackageParser.PackageParserException {
             // Do not actually parse the package for testing
             return null;
diff --git a/services/tests/servicestests/src/com/android/server/pm/ScanRequestBuilder.java b/services/tests/servicestests/src/com/android/server/pm/ScanRequestBuilder.java
index 34a3f86..11f154b 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ScanRequestBuilder.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ScanRequestBuilder.java
@@ -16,12 +16,13 @@
 
 package com.android.server.pm;
 
-import android.content.pm.PackageParser;
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.ParsedPackage;
 import android.os.UserHandle;
 
 class ScanRequestBuilder {
-    private final PackageParser.Package mPkg;
-    private PackageParser.Package mOldPkg;
+    private final ParsedPackage mPkg;
+    private AndroidPackage mOldPkg;
     private SharedUserSetting mSharedUserSetting;
     private PackageSetting mPkgSetting;
     private PackageSetting mDisabledPkgSetting;
@@ -32,11 +33,11 @@
     private UserHandle mUser;
     private boolean mIsPlatformPackage;
 
-    ScanRequestBuilder(PackageParser.Package pkg) {
+    ScanRequestBuilder(ParsedPackage pkg) {
         this.mPkg = pkg;
     }
 
-    public ScanRequestBuilder setOldPkg(PackageParser.Package oldPkg) {
+    public ScanRequestBuilder setOldPkg(AndroidPackage oldPkg) {
         this.mOldPkg = oldPkg;
         return this;
     }
diff --git a/services/tests/servicestests/src/com/android/server/pm/ScanTests.java b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
index 74ef034..997348d 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
@@ -35,13 +35,17 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.nullable;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
 import android.Manifest;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
-import android.content.pm.PackageParser;
 import android.content.pm.SharedLibraryInfo;
+import android.content.pm.parsing.PackageImpl;
+import android.content.pm.parsing.ParsedPackage;
+import android.content.pm.parsing.ParsingPackage;
+import android.content.res.TypedArray;
 import android.os.Environment;
 import android.os.UserHandle;
 import android.os.UserManagerInternal;
@@ -60,6 +64,7 @@
 import org.mockito.junit.MockitoJUnitRunner;
 
 import java.io.File;
+import java.util.UUID;
 
 @RunWith(MockitoJUnitRunner.class)
 @Presubmit
@@ -68,6 +73,9 @@
 
     private static final String DUMMY_PACKAGE_NAME = "some.app.to.test";
 
+    private static final UUID UUID_ONE = UUID.randomUUID();
+    private static final UUID UUID_TWO = UUID.randomUUID();
+
     @Mock
     PackageAbiHelper mMockPackageAbiHelper;
     @Mock
@@ -92,25 +100,25 @@
     @Before
     public void setupDefaultAbiBehavior() throws Exception {
         when(mMockPackageAbiHelper.derivePackageAbi(
-                any(PackageParser.Package.class), nullable(String.class), anyBoolean()))
+                any(ParsedPackage.class), nullable(String.class), anyBoolean()))
                 .thenReturn(new Pair<>(
                         new PackageAbiHelper.Abis("derivedPrimary", "derivedSecondary"),
                         new PackageAbiHelper.NativeLibraryPaths(
                                 "derivedRootDir", true, "derivedNativeDir", "derivedNativeDir2")));
         when(mMockPackageAbiHelper.getNativeLibraryPaths(
-                any(PackageParser.Package.class), any(File.class)))
+                any(ParsedPackage.class), any(File.class)))
                 .thenReturn(new PackageAbiHelper.NativeLibraryPaths(
                         "getRootDir", true, "getNativeDir", "getNativeDir2"
                 ));
         when(mMockPackageAbiHelper.getBundledAppAbis(
-                any(PackageParser.Package.class)))
+                any(ParsedPackage.class)))
                 .thenReturn(new PackageAbiHelper.Abis("bundledPrimary", "bundledSecondary"));
     }
 
     @Test
     public void newInstallSimpleAllNominal() throws Exception {
         final PackageManagerService.ScanRequest scanRequest =
-                createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
+                createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME))
                         .addScanFlag(PackageManagerService.SCAN_NEW_INSTALL)
                         .addScanFlag(PackageManagerService.SCAN_AS_FULL_APP)
                         .build();
@@ -128,7 +136,7 @@
         when(mMockUserManager.getUserIds()).thenReturn(userIds);
 
         final PackageManagerService.ScanRequest scanRequest =
-                createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
+                createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME))
                         .setRealPkgName(null)
                         .addScanFlag(PackageManagerService.SCAN_NEW_INSTALL)
                         .addScanFlag(PackageManagerService.SCAN_AS_FULL_APP)
@@ -143,7 +151,7 @@
     @Test
     public void installRealPackageName() throws Exception {
         final PackageManagerService.ScanRequest scanRequest =
-                createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
+                createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME))
                         .setRealPkgName("com.package.real")
                         .build();
 
@@ -154,7 +162,7 @@
         final PackageManagerService.ScanRequest scanRequestNoRealPkg =
                 createBasicScanRequestBuilder(
                         createBasicPackage(DUMMY_PACKAGE_NAME)
-                                .setRealPackageName("com.package.real").build())
+                                .setRealPackage("com.package.real"))
                         .build();
 
         final PackageManagerService.ScanResult scanResultNoReal = executeScan(scanRequestNoRealPkg);
@@ -170,7 +178,7 @@
                 .setSecondaryCpuAbiString("secondaryCpuAbi")
                 .build();
         final PackageManagerService.ScanRequest scanRequest =
-                createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
+                createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME))
                         .addScanFlag(PackageManagerService.SCAN_AS_FULL_APP)
                         .setPkgSetting(pkgSetting)
                         .build();
@@ -202,7 +210,7 @@
                         .build();
 
         final PackageManagerService.ScanRequest scanRequest =
-                createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
+                createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME))
                         .setPkgSetting(existingPkgSetting)
                         .build();
 
@@ -214,17 +222,18 @@
 
     @Test
     public void installStaticSharedLibrary() throws Exception {
-        final PackageParser.Package pkg = createBasicPackage("static.lib.pkg.123")
-                .setStaticSharedLib("static.lib", 123L)
-                .setManifestPackageName("static.lib.pkg")
+        final ParsedPackage pkg = createBasicPackage("static.lib.pkg")
+                .setStaticSharedLibName("static.lib")
+                .setStaticSharedLibVersion(123L)
+                .hideAsParsed()
+                .setPackageName("static.lib.pkg.123")
                 .setVersionCodeMajor(1)
                 .setVersionCode(234)
                 .setBaseCodePath("/some/path.apk")
-                .addSplitCodePath("/some/other/path.apk")
-                .build();
+                .setSplitCodePaths(new String[] {"/some/other/path.apk"});
 
-        final PackageManagerService.ScanRequest scanRequest = new ScanRequestBuilder(
-                pkg).setUser(UserHandle.of(0)).build();
+        final PackageManagerService.ScanRequest scanRequest = new ScanRequestBuilder(pkg)
+                .setUser(UserHandle.of(0)).build();
 
 
         final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
@@ -245,15 +254,14 @@
 
     @Test
     public void installDynamicLibraries() throws Exception {
-        final PackageParser.Package pkg = createBasicPackage("dynamic.lib.pkg")
-                .setManifestPackageName("dynamic.lib.pkg")
+        final ParsedPackage pkg = createBasicPackage("dynamic.lib.pkg")
                 .addLibraryName("liba")
                 .addLibraryName("libb")
+                .hideAsParsed()
                 .setVersionCodeMajor(1)
                 .setVersionCode(234)
                 .setBaseCodePath("/some/path.apk")
-                .addSplitCodePath("/some/other/path.apk")
-                .build();
+                .setSplitCodePaths(new String[] {"/some/other/path.apk"});
 
         final PackageManagerService.ScanRequest scanRequest =
                 new ScanRequestBuilder(pkg).setUser(UserHandle.of(0)).build();
@@ -295,15 +303,15 @@
                         .setVolumeUuid("someUuid")
                         .build();
 
-        final PackageParser.Package basicPackage = createBasicPackage(DUMMY_PACKAGE_NAME)
-                .setApplicationInfoVolumeUuid("someNewUuid")
-                .build();
+        final ParsedPackage basicPackage = createBasicPackage(DUMMY_PACKAGE_NAME)
+                .hideAsParsed()
+                .setApplicationVolumeUuid(UUID_TWO.toString());
 
 
         final PackageManagerService.ScanResult scanResult = executeScan(
                 new ScanRequestBuilder(basicPackage).setPkgSetting(pkgSetting).build());
 
-        assertThat(scanResult.pkgSetting.volumeUuid, is("someNewUuid"));
+        assertThat(scanResult.pkgSetting.volumeUuid, is(UUID_TWO.toString()));
     }
 
     @Test
@@ -311,10 +319,10 @@
         final PackageSetting pkgSetting =
                 createBasicPackageSettingBuilder(DUMMY_PACKAGE_NAME).build();
 
-        final PackageParser.Package basicPackage =
+        final ParsedPackage basicPackage =
                 createBasicPackage(DUMMY_PACKAGE_NAME)
-                        .setCpuAbiOVerride("testOverride")
-                        .build();
+                        .hideAsParsed()
+                        .setCpuAbiOverride("testOverride");
 
 
         final PackageManagerService.ScanResult scanResult = executeScan(new ScanRequestBuilder(
@@ -331,9 +339,9 @@
         final PackageSetting originalPkgSetting =
                 createBasicPackageSettingBuilder("original.package").build();
 
-        final PackageParser.Package basicPackage =
+        final ParsedPackage basicPackage =
                 createBasicPackage(DUMMY_PACKAGE_NAME)
-                        .build();
+                        .hideAsParsed();
 
 
         final PackageManagerService.ScanResult result =
@@ -341,7 +349,7 @@
                         .setOriginalPkgSetting(originalPkgSetting)
                         .build());
 
-        assertThat(result.request.pkg.packageName, is("original.package"));
+        assertThat(result.request.parsedPackage.getPackageName(), is("original.package"));
     }
 
     @Test
@@ -354,7 +362,7 @@
                         .build();
 
         final PackageManagerService.ScanRequest scanRequest =
-                createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
+                createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME))
                         .setPkgSetting(existingPkgSetting)
                         .addScanFlag(SCAN_AS_FULL_APP)
                         .build();
@@ -375,7 +383,7 @@
                         .build();
 
         final PackageManagerService.ScanRequest scanRequest =
-                createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
+                createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME))
                         .setPkgSetting(existingPkgSetting)
                         .addScanFlag(SCAN_AS_INSTANT_APP)
                         .build();
@@ -394,7 +402,7 @@
                         .build();
 
         final PackageManagerService.ScanRequest scanRequest =
-                createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
+                createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME))
                         .setPkgSetting(existingPkgSetting)
                         .setDisabledPkgSetting(existingPkgSetting)
                         .addScanFlag(SCAN_NEW_INSTALL)
@@ -402,15 +410,14 @@
 
         final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
 
-        assertThat(scanResult.request.pkg.applicationInfo.flags,
+        assertThat(scanResult.request.parsedPackage.getFlags(),
                 hasFlag(ApplicationInfo.FLAG_UPDATED_SYSTEM_APP));
     }
 
     @Test
     public void factoryTestFlagSet() throws Exception {
-        final PackageParser.Package basicPackage = createBasicPackage(DUMMY_PACKAGE_NAME)
-                .addPermissionRequest(Manifest.permission.FACTORY_TEST)
-                .build();
+        final ParsingPackage basicPackage = createBasicPackage(DUMMY_PACKAGE_NAME)
+                .addRequestedPermission(Manifest.permission.FACTORY_TEST);
 
         final PackageManagerService.ScanResult scanResult = PackageManagerService.scanPackageOnlyLI(
                 createBasicScanRequestBuilder(basicPackage).build(),
@@ -418,15 +425,15 @@
                 true /*isUnderFactoryTest*/,
                 System.currentTimeMillis());
 
-        assertThat(scanResult.request.pkg.applicationInfo.flags,
+        assertThat(scanResult.request.parsedPackage.getFlags(),
                 hasFlag(ApplicationInfo.FLAG_FACTORY_TEST));
     }
 
     @Test
     public void scanSystemApp_isOrphanedTrue() throws Exception {
-        final PackageParser.Package pkg = createBasicPackage(DUMMY_PACKAGE_NAME)
-                .addApplicationInfoFlag(ApplicationInfo.FLAG_SYSTEM)
-                .build();
+        final ParsedPackage pkg = createBasicPackage(DUMMY_PACKAGE_NAME)
+                .hideAsParsed()
+                .setSystem(true);
 
         final PackageManagerService.ScanRequest scanRequest =
                 createBasicScanRequestBuilder(pkg)
@@ -481,22 +488,29 @@
                 .setResourcePath(createResourcePath(packageName));
     }
 
-    private static ScanRequestBuilder createBasicScanRequestBuilder(PackageParser.Package pkg) {
+    private static ScanRequestBuilder createBasicScanRequestBuilder(ParsingPackage pkg) {
+        return new ScanRequestBuilder(pkg.hideAsParsed())
+                .setUser(UserHandle.of(0));
+    }
+
+    private static ScanRequestBuilder createBasicScanRequestBuilder(ParsedPackage pkg) {
         return new ScanRequestBuilder(pkg)
                 .setUser(UserHandle.of(0));
     }
 
-
-    private static PackageBuilder createBasicPackage(String packageName) {
-        return new PackageBuilder(packageName)
+    private static ParsingPackage createBasicPackage(String packageName) {
+        // TODO(b/135203078): Make this use PackageImpl.forParsing and separate the steps
+        return new PackageImpl(packageName, null, mock(TypedArray.class), false)
                 .setCodePath("/data/tmp/randompath")
                 .setApplicationInfoCodePath(createCodePath(packageName))
                 .setApplicationInfoResourcePath(createResourcePath(packageName))
-                .setApplicationInfoVolumeUuid("volumeUuid")
+                .setApplicationVolumeUuid(UUID_ONE.toString())
                 .setBaseCodePath("/data/tmp/randompath/base.apk")
-                .addUsesStaticLibrary("some.static.library", 234L)
-                .addUsesStaticLibrary("some.other.static.library", 456L)
-                .setApplicationInfoNativeLibraryRootDir("/data/tmp/randompath/base.apk:/lib")
+                .addUsesStaticLibrary("some.static.library")
+                .addUsesStaticLibraryVersion(234L)
+                .addUsesStaticLibrary("some.other.static.library")
+                .addUsesStaticLibraryVersion(456L)
+                .setNativeLibraryRootDir("/data/tmp/randompath/base.apk:/lib")
                 .setVersionCodeMajor(1)
                 .setVersionCode(2345);
     }
@@ -508,20 +522,18 @@
         final PackageSetting pkgSetting = scanResult.pkgSetting;
         assertBasicPackageSetting(scanResult, packageName, isInstant, pkgSetting);
 
-        final ApplicationInfo applicationInfo = pkgSetting.pkg.applicationInfo;
+        final ApplicationInfo applicationInfo = pkgSetting.pkg.toAppInfo();
         assertBasicApplicationInfo(scanResult, applicationInfo);
-
     }
 
     private static void assertBasicPackageSetting(PackageManagerService.ScanResult scanResult,
             String packageName, boolean isInstant, PackageSetting pkgSetting) {
-        assertThat(pkgSetting.pkg.packageName, is(packageName));
+        assertThat(pkgSetting.pkg.getPackageName(), is(packageName));
         assertThat(pkgSetting.getInstantApp(0), is(isInstant));
         assertThat(pkgSetting.usesStaticLibraries,
                 arrayContaining("some.static.library", "some.other.static.library"));
         assertThat(pkgSetting.usesStaticLibrariesVersions, is(new long[]{234L, 456L}));
-        assertThat(pkgSetting.pkg, is(scanResult.request.pkg));
-        assertThat(pkgSetting.pkg.mExtras, is(pkgSetting));
+        assertThat(pkgSetting.pkg, is(scanResult.request.parsedPackage));
         assertThat(pkgSetting.codePath, is(new File(createCodePath(packageName))));
         assertThat(pkgSetting.resourcePath, is(new File(createResourcePath(packageName))));
         assertThat(pkgSetting.versionCode, is(PackageInfo.composeLongVersionCode(1, 2345)));
@@ -529,20 +541,21 @@
 
     private static void assertBasicApplicationInfo(PackageManagerService.ScanResult scanResult,
             ApplicationInfo applicationInfo) {
-        assertThat(applicationInfo.processName, is(scanResult.request.pkg.packageName));
+        assertThat(applicationInfo.processName,
+                is(scanResult.request.parsedPackage.getPackageName()));
 
         final int uid = applicationInfo.uid;
         assertThat(UserHandle.getUserId(uid), is(UserHandle.USER_SYSTEM));
 
         final String calculatedCredentialId = Environment.getDataUserCePackageDirectory(
                 applicationInfo.volumeUuid, UserHandle.USER_SYSTEM,
-                scanResult.request.pkg.packageName).getAbsolutePath();
+                scanResult.request.parsedPackage.getPackageName()).getAbsolutePath();
         assertThat(applicationInfo.credentialProtectedDataDir, is(calculatedCredentialId));
         assertThat(applicationInfo.dataDir, is(applicationInfo.credentialProtectedDataDir));
     }
 
     private static void assertAbiAndPathssDerived(PackageManagerService.ScanResult scanResult) {
-        final ApplicationInfo applicationInfo = scanResult.pkgSetting.pkg.applicationInfo;
+        final ApplicationInfo applicationInfo = scanResult.pkgSetting.pkg.toAppInfo();
         assertThat(applicationInfo.primaryCpuAbi, is("derivedPrimary"));
         assertThat(applicationInfo.secondaryCpuAbi, is("derivedSecondary"));
 
@@ -554,7 +567,7 @@
     }
 
     private static void assertPathsNotDerived(PackageManagerService.ScanResult scanResult) {
-        final ApplicationInfo applicationInfo = scanResult.pkgSetting.pkg.applicationInfo;
+        final ApplicationInfo applicationInfo = scanResult.pkgSetting.pkg.toAppInfo();
         assertThat(applicationInfo.nativeLibraryRootDir, is("getRootDir"));
         assertThat(scanResult.pkgSetting.legacyNativeLibraryPathString, is("getRootDir"));
         assertThat(applicationInfo.nativeLibraryRootRequiresIsa, is(true));
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java
index 790f2b4..0b0f6a7 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java
@@ -37,8 +37,9 @@
 import android.content.Context;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
-import android.content.pm.PackageParser;
 import android.content.pm.UserInfo;
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.PackageImpl;
 import android.os.Looper;
 import android.os.SystemProperties;
 import android.os.UserManager;
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java
index 3a55c22..66a4946 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java
@@ -22,8 +22,11 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
-import android.content.pm.ApplicationInfo;
 import android.content.pm.SharedLibraryInfo;
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.PackageImpl;
+import android.content.pm.parsing.ParsedPackage;
+import android.content.pm.parsing.ParsingPackage;
 import android.util.SparseArray;
 
 import androidx.test.filters.SmallTest;
@@ -51,17 +54,18 @@
             DelegateLastClassLoader.class.getName();
 
     private static class TestData {
-        ApplicationInfo info;
+        AndroidPackage pkg;
         boolean[] pathsWithCode;
     }
 
     private TestData createMockApplicationInfo(String baseClassLoader, boolean addSplits,
-            boolean addSplitDependencies) {
-        ApplicationInfo ai = new ApplicationInfo();
+            boolean addSplitDependencies, boolean isolatedSplitLoading) {
         String codeDir = "/data/app/mock.android.com";
-        ai.setBaseCodePath(codeDir + "/base.dex");
-        ai.classLoaderName = baseClassLoader;
-        ai.privateFlags = ai.privateFlags | ApplicationInfo.PRIVATE_FLAG_ISOLATED_SPLIT_LOADING;
+        ParsingPackage parsingPackage = PackageImpl.forParsing("mock.android.com")
+                .setClassLoaderName(baseClassLoader);
+
+        parsingPackage.setIsolatedSplitLoading(isolatedSplitLoading);
+
         boolean[] pathsWithCode;
         if (!addSplits) {
             pathsWithCode = new boolean[] {true};
@@ -70,7 +74,7 @@
             Arrays.fill(pathsWithCode, true);
             pathsWithCode[7] = false;  // config split
 
-            ai.setSplitCodePaths(new String[]{
+            String[] splitCodePaths = new String[]{
                     codeDir + "/base-1.dex",
                     codeDir + "/base-2.dex",
                     codeDir + "/base-3.dex",
@@ -78,32 +82,51 @@
                     codeDir + "/base-5.dex",
                     codeDir + "/base-6.dex",
                     codeDir + "/config-split-7.dex",
-                    codeDir + "/feature-no-deps.dex"});
+                    codeDir + "/feature-no-deps.dex"
+            };
 
-            ai.splitClassLoaderNames = new String[]{
-                    DELEGATE_LAST_CLASS_LOADER_NAME,
-                    DELEGATE_LAST_CLASS_LOADER_NAME,
-                    PATH_CLASS_LOADER_NAME,
-                    DEX_CLASS_LOADER_NAME,
-                    PATH_CLASS_LOADER_NAME,
-                    null,   // A null class loader name should default to PathClassLoader.
-                    null,   // The config split gets a null class loader.
-                    null};  // The feature split with no dependency and no specified class loader.
+            String[] splitNames = new String[splitCodePaths.length];
+            int[] splitRevisionCodes = new int[splitCodePaths.length];
+            SparseArray<int[]> splitDependencies = null;
+
             if (addSplitDependencies) {
-                ai.splitDependencies = new SparseArray<>(ai.splitClassLoaderNames.length + 1);
-                ai.splitDependencies.put(0, new int[] {-1}); // base has no dependency
-                ai.splitDependencies.put(1, new int[] {2}); // split 1 depends on 2
-                ai.splitDependencies.put(2, new int[] {4}); // split 2 depends on 4
-                ai.splitDependencies.put(3, new int[] {4}); // split 3 depends on 4
-                ai.splitDependencies.put(4, new int[] {0}); // split 4 depends on base
-                ai.splitDependencies.put(5, new int[] {0}); // split 5 depends on base
-                ai.splitDependencies.put(6, new int[] {5}); // split 6 depends on 5
+                splitDependencies = new SparseArray<>(splitCodePaths.length);
+                splitDependencies.put(0, new int[] {-1}); // base has no dependency
+                splitDependencies.put(1, new int[] {2}); // split 1 depends on 2
+                splitDependencies.put(2, new int[] {4}); // split 2 depends on 4
+                splitDependencies.put(3, new int[] {4}); // split 3 depends on 4
+                splitDependencies.put(4, new int[] {0}); // split 4 depends on base
+                splitDependencies.put(5, new int[] {0}); // split 5 depends on base
+                splitDependencies.put(6, new int[] {5}); // split 6 depends on 5
                 // Do not add the config split to the dependency list.
                 // Do not add the feature split with no dependency to the dependency list.
             }
+
+            parsingPackage
+                    .asSplit(
+                            splitNames,
+                            splitCodePaths,
+                            splitRevisionCodes,
+                            splitDependencies
+                    )
+                    .setSplitClassLoaderName(0, DELEGATE_LAST_CLASS_LOADER_NAME)
+                    .setSplitClassLoaderName(1, DELEGATE_LAST_CLASS_LOADER_NAME)
+                    .setSplitClassLoaderName(2, PATH_CLASS_LOADER_NAME)
+                    .setSplitClassLoaderName(3, DEX_CLASS_LOADER_NAME)
+                    .setSplitClassLoaderName(4, PATH_CLASS_LOADER_NAME)
+                    // A null class loader name should default to PathClassLoader
+                    .setSplitClassLoaderName(5, null)
+                    // The config split gets a null class loader
+                    .setSplitClassLoaderName(6, null)
+                    // The feature split with no dependency and no specified class loader.
+                    .setSplitClassLoaderName(7, null);
         }
+
+        ParsedPackage parsedPackage = parsingPackage.hideAsParsed()
+                .setBaseCodePath(codeDir + "/base.dex");
+
         TestData data = new TestData();
-        data.info = ai;
+        data.pkg = parsedPackage.hideAsFinal();
         data.pathsWithCode = pathsWithCode;
         return data;
     }
@@ -118,11 +141,11 @@
 
     @Test
     public void testSplitChain() {
-        TestData data = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, true, true);
+        TestData data = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, true, true, true);
         List<SharedLibraryInfo> sharedLibrary =
                 createMockSharedLibrary(new String[] {"a.dex", "b.dex"});
         String[] contexts = DexoptUtils.getClassLoaderContexts(
-                data.info, sharedLibrary, data.pathsWithCode);
+                data.pkg, sharedLibrary, data.pathsWithCode);
 
         assertEquals(9, contexts.length);
         assertEquals("PCL[]{PCL[a.dex:b.dex]}", contexts[0]);
@@ -139,11 +162,11 @@
 
     @Test
     public void testSplitChainNoSplitDependencies() {
-        TestData data = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, true, false);
+        TestData data = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, true, false, true);
         List<SharedLibraryInfo> sharedLibrary =
                 createMockSharedLibrary(new String[] {"a.dex", "b.dex"});
         String[] contexts = DexoptUtils.getClassLoaderContexts(
-                data.info, sharedLibrary, data.pathsWithCode);
+                data.pkg, sharedLibrary, data.pathsWithCode);
 
         assertEquals(9, contexts.length);
         assertEquals("PCL[]{PCL[a.dex:b.dex]}", contexts[0]);
@@ -167,11 +190,9 @@
 
     @Test
     public void testSplitChainNoIsolationNoSharedLibrary() {
-        TestData data = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, true, true);
-        data.info.privateFlags = data.info.privateFlags
-                & (~ApplicationInfo.PRIVATE_FLAG_ISOLATED_SPLIT_LOADING);
+        TestData data = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, true, true, false);
         String[] contexts = DexoptUtils.getClassLoaderContexts(
-                data.info, null, data.pathsWithCode);
+                data.pkg, null, data.pathsWithCode);
 
         assertEquals(9, contexts.length);
         assertEquals("PCL[]", contexts[0]);
@@ -192,9 +213,9 @@
     @Test
     public void testSplitChainNoSharedLibraries() {
         TestData data = createMockApplicationInfo(
-                DELEGATE_LAST_CLASS_LOADER_NAME, true, true);
+                DELEGATE_LAST_CLASS_LOADER_NAME, true, true, true);
         String[] contexts = DexoptUtils.getClassLoaderContexts(
-                data.info, null, data.pathsWithCode);
+                data.pkg, null, data.pathsWithCode);
 
         assertEquals(9, contexts.length);
         assertEquals("DLC[]", contexts[0]);
@@ -211,11 +232,11 @@
     @Test
     public void testSplitChainWithNullPrimaryClassLoader() {
         // A null classLoaderName should mean PathClassLoader.
-        TestData data = createMockApplicationInfo(null, true, true);
+        TestData data = createMockApplicationInfo(null, true, true, true);
         List<SharedLibraryInfo> sharedLibrary =
                 createMockSharedLibrary(new String[] {"a.dex", "b.dex"});
         String[] contexts = DexoptUtils.getClassLoaderContexts(
-                data.info, sharedLibrary, data.pathsWithCode);
+                data.pkg, sharedLibrary, data.pathsWithCode);
 
         assertEquals(9, contexts.length);
         assertEquals("PCL[]{PCL[a.dex:b.dex]}", contexts[0]);
@@ -233,11 +254,11 @@
 
     @Test
     public void tesNoSplits() {
-        TestData data = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, false, false);
+        TestData data = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, false, false, true);
         List<SharedLibraryInfo> sharedLibrary =
                 createMockSharedLibrary(new String[] {"a.dex", "b.dex"});
         String[] contexts = DexoptUtils.getClassLoaderContexts(
-                data.info, sharedLibrary, data.pathsWithCode);
+                data.pkg, sharedLibrary, data.pathsWithCode);
 
         assertEquals(1, contexts.length);
         assertEquals("PCL[]{PCL[a.dex:b.dex]}", contexts[0]);
@@ -245,11 +266,11 @@
 
     @Test
     public void tesNoSplitsNullClassLoaderName() {
-        TestData data = createMockApplicationInfo(null, false, false);
+        TestData data = createMockApplicationInfo(null, false, false, true);
         List<SharedLibraryInfo> sharedLibrary =
                 createMockSharedLibrary(new String[] {"a.dex", "b.dex"});
         String[] contexts = DexoptUtils.getClassLoaderContexts(
-                data.info, sharedLibrary, data.pathsWithCode);
+                data.pkg, sharedLibrary, data.pathsWithCode);
 
         assertEquals(1, contexts.length);
         assertEquals("PCL[]{PCL[a.dex:b.dex]}", contexts[0]);
@@ -258,11 +279,11 @@
     @Test
     public void tesNoSplitDelegateLast() {
         TestData data = createMockApplicationInfo(
-                DELEGATE_LAST_CLASS_LOADER_NAME, false, false);
+                DELEGATE_LAST_CLASS_LOADER_NAME, false, false, true);
         List<SharedLibraryInfo> sharedLibrary =
                 createMockSharedLibrary(new String[] {"a.dex", "b.dex"});
         String[] contexts = DexoptUtils.getClassLoaderContexts(
-                data.info, sharedLibrary, data.pathsWithCode);
+                data.pkg, sharedLibrary, data.pathsWithCode);
 
         assertEquals(1, contexts.length);
         assertEquals("DLC[]{PCL[a.dex:b.dex]}", contexts[0]);
@@ -270,9 +291,9 @@
 
     @Test
     public void tesNoSplitsNoSharedLibraries() {
-        TestData data = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, false, false);
+        TestData data = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, false, false, true);
         String[] contexts = DexoptUtils.getClassLoaderContexts(
-                data.info, null, data.pathsWithCode);
+                data.pkg, null, data.pathsWithCode);
 
         assertEquals(1, contexts.length);
         assertEquals("PCL[]", contexts[0]);
@@ -281,9 +302,9 @@
     @Test
     public void tesNoSplitDelegateLastNoSharedLibraries() {
         TestData data = createMockApplicationInfo(
-                DELEGATE_LAST_CLASS_LOADER_NAME, false, false);
+                DELEGATE_LAST_CLASS_LOADER_NAME, false, false, true);
         String[] contexts = DexoptUtils.getClassLoaderContexts(
-                data.info, null, data.pathsWithCode);
+                data.pkg, null, data.pathsWithCode);
 
         assertEquals(1, contexts.length);
         assertEquals("DLC[]", contexts[0]);
@@ -291,13 +312,13 @@
 
     @Test
     public void testContextWithNoCode() {
-        TestData data = createMockApplicationInfo(null, true, false);
+        TestData data = createMockApplicationInfo(null, true, false, true);
         Arrays.fill(data.pathsWithCode, false);
 
         List<SharedLibraryInfo> sharedLibrary =
                 createMockSharedLibrary(new String[] {"a.dex", "b.dex"});
         String[] contexts = DexoptUtils.getClassLoaderContexts(
-                data.info, sharedLibrary, data.pathsWithCode);
+                data.pkg, sharedLibrary, data.pathsWithCode);
 
         assertEquals(9, contexts.length);
         assertEquals(null, contexts[0]);
@@ -312,12 +333,12 @@
 
     @Test
     public void testContextBaseNoCode() {
-        TestData data = createMockApplicationInfo(null, true, true);
+        TestData data = createMockApplicationInfo(null, true, true, true);
         data.pathsWithCode[0] = false;
         List<SharedLibraryInfo> sharedLibrary =
                 createMockSharedLibrary(new String[] {"a.dex", "b.dex"});
         String[] contexts = DexoptUtils.getClassLoaderContexts(
-                data.info, sharedLibrary, data.pathsWithCode);
+                data.pkg, sharedLibrary, data.pathsWithCode);
 
         assertEquals(9, contexts.length);
         assertEquals(null, contexts[0]);