Deprecate PackageParser#Package

Replaces PackageParser#Package and it's related structures with
ParsingPackage, ParsedPackage, and AndroidPackage.

This is a large scoped CL, the first step in an eventual goal
to refactor how data is handled in the package parsing and install
process. It introduces as few logic changes as necessary. Mostly
migrating to interfaces and renaming, moving parsing data calls into
3 separate interfaces that outline the intended flow for parsing.

ParsingPackage is built and used during what was PackageParser, now
replaced by ApkParseUtils and it's related classes. This is almost
exactly what was parsed from the XML/files on disk.

ParsedPackage is used when the object exits PackageParser and is
adjusted by PackageManagerService to what is considered the final
"parsed" state, adjusted from literal values, but consistent given
the same APK on disk. This should eventually be moved out of PMS
and possibly collapsed into the previous interface entirely.

AndroidPackage is the final state of the package after parsing and
adjustment has completed and no more mutations should be expected.
There are a few exceptions to this, included in AndroidPackageWrite,
which will eventually be refactored into PackageSetting or another
state class.

This marks PackageParser#Package and all the old infrastructure with
@Deprecated, as none of them are used internally. All usages were
converted, and the legacy Package is only built for un-converted tests
and @UnsupportedAppUsage methods.

There are numerous TODOs still outstanding, but addressing them
in this initial CL would introduce several logic changes. They've been
marked with the bug number and will be handled in follow ups.

This is being merged with caution thrown to the wind because
testing this on devices and in development will be the best way
to debug differences introduced by the migration. Getting it merged
as early as possible gives the most amount of time to fix regressions.

Waiting for tests of all the functionality could take literal years
before covering enough to merge this with all regressions verified.

Given a sample size of 4 heap dumps and the caveat it was taken very
early in the migration, there is a memory overhead of about 200 KB
versus the legacy implementation. This should be verified more
accurately and addressed in follow ups.

This CL also kills child/parent package support, since that's
broken already, and difficult to support with the new interface
structure.

Bug: 135203078

Test: booted an emulator, works generally as expected

Specific tests which failed / failed to build were fixed, but because
not all tests are currently passing before this change, not all were
verified.

Change-Id: I4ba050c228e6c60b8f63a9e3347b1f9a57ef794a
diff --git a/Android.bp b/Android.bp
index 6fc233c..69f5595 100644
--- a/Android.bp
+++ b/Android.bp
@@ -305,7 +305,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",
@@ -435,7 +435,7 @@
     name: "framework-atb-backward-compatibility",
     installable: true,
     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 8d91144..5698dfe 100644
--- a/config/preloaded-classes
+++ b/config/preloaded-classes
@@ -877,7 +877,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
@@ -921,10 +921,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
@@ -959,7 +959,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 415c242..29f243f 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -1379,7 +1379,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/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java
index f28b85c..7465498 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/core/java/android/content/pm/PackageManagerInternal.java
@@ -28,6 +28,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;
@@ -315,7 +317,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);
 
     /**
@@ -394,7 +396,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.
@@ -486,13 +488,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.
@@ -523,17 +529,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);
 
@@ -567,7 +575,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.
@@ -641,7 +649,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);
@@ -652,14 +661,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);
@@ -793,7 +802,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/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 0b157fa..2ded5dc 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";
 
@@ -897,7 +907,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
@@ -1043,7 +1053,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
@@ -1051,21 +1061,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);
@@ -1077,19 +1120,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());
@@ -1100,13 +1136,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);
@@ -1114,7 +1150,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();
 
@@ -1124,14 +1161,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);
 
@@ -1180,7 +1217,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;
         }
@@ -1195,9 +1232,9 @@
             }
 
             final byte[] bytes = IoUtils.readFileAsByteArray(cacheFile.getAbsolutePath());
-            Package p = fromCacheEntry(bytes);
+            ParsedPackage p = fromCacheEntry(bytes);
             if (mCallback != null) {
-                String[] overlayApks = mCallback.getOverlayApks(p.packageName);
+                String[] overlayApks = mCallback.getOverlayApks(p.getPackageName());
                 if (overlayApks != null && overlayApks.length > 0) {
                     for (String overlayApk : overlayApks) {
                         // If a static RRO is updated, return null.
@@ -1221,7 +1258,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;
         }
@@ -1260,7 +1297,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);
@@ -1324,10 +1362,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
@@ -1527,8 +1566,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);
@@ -1707,7 +1749,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 {
 
@@ -2487,8 +2529,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 + " "
@@ -2958,7 +2998,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;
@@ -3006,7 +3046,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)) {
@@ -3026,7 +3066,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;
@@ -3588,9 +3628,6 @@
             owner.mRequiredAccountType = requiredAccountType;
         }
 
-        owner.mForceQueryable =
-                sa.getBoolean(R.styleable.AndroidManifestApplication_forceQueryable, false);
-
         if (sa.getBoolean(
                 com.android.internal.R.styleable.AndroidManifestApplication_debuggable,
                 false)) {
@@ -4052,89 +4089,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
      */
@@ -5846,7 +5800,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,
@@ -6541,7 +6495,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
@@ -6649,9 +6606,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);
@@ -6757,9 +6711,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;
@@ -7263,9 +7214,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) {
@@ -7281,7 +7229,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;
@@ -7391,12 +7339,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.
          */
@@ -7468,6 +7412,10 @@
         };
     }
 
+    /**
+     * @deprecated use a {@link ComponentParseUtils.ParsedComponent}
+     */
+    @Deprecated
     public static abstract class Component<II extends IntentInfo> {
         @UnsupportedAppUsage
         public final ArrayList<II> intents;
@@ -7648,6 +7596,10 @@
         }
     }
 
+    /**
+     * @deprecated use {@link ComponentParseUtils.ParsedPermission}
+     */
+    @Deprecated
     public final static class Permission extends Component<IntentInfo> implements Parcelable {
         @UnsupportedAppUsage
         public final PermissionInfo info;
@@ -7722,6 +7674,10 @@
         };
     }
 
+    /**
+     * @deprecated use {@link ComponentParseUtils.ParsedPermissionGroup}
+     */
+    @Deprecated
     public final static class PermissionGroup extends Component<IntentInfo> implements Parcelable {
         @UnsupportedAppUsage
         public final PermissionGroupInfo info;
@@ -7821,7 +7777,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());
@@ -7878,7 +7839,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;
@@ -7918,6 +7884,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;
@@ -7937,7 +7908,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;
@@ -7949,7 +7925,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;
@@ -7961,6 +7942,10 @@
         return pgi;
     }
 
+    /**
+     * @deprecated use {@link ComponentParseUtils.ParsedActivity}
+     */
+    @Deprecated
     public final static class Activity extends Component<ActivityIntentInfo> implements Parcelable {
         @UnsupportedAppUsage
         public final ActivityInfo info;
@@ -8076,7 +8061,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;
@@ -8094,6 +8084,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;
@@ -8107,6 +8102,10 @@
         return ai;
     }
 
+    /**
+     * @deprecated use {@link ComponentParseUtils.ParsedService}
+     */
+    @Deprecated
     public final static class Service extends Component<ServiceIntentInfo> implements Parcelable {
         @UnsupportedAppUsage
         public final ServiceInfo info;
@@ -8168,7 +8167,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;
@@ -8186,6 +8190,10 @@
         return si;
     }
 
+    /**
+     * @deprecated use {@link ComponentParseUtils.ParsedProvider}
+     */
+    @Deprecated
     public final static class Provider extends Component<ProviderIntentInfo> implements Parcelable {
         @UnsupportedAppUsage
         public final ProviderInfo info;
@@ -8266,7 +8274,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;
@@ -8289,6 +8302,10 @@
         return pi;
     }
 
+    /**
+     * @deprecated use {@link ComponentParseUtils.ParsedInstrumentation}
+     */
+    @Deprecated
     public final static class Instrumentation extends Component<IntentInfo> implements
             Parcelable {
         @UnsupportedAppUsage
@@ -8349,7 +8366,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;
@@ -8361,6 +8383,10 @@
         return ii;
     }
 
+    /**
+     * @deprecated use {@link ComponentParseUtils.ParsedIntentInfo}
+     */
+    @Deprecated
     public static abstract class IntentInfo extends IntentFilter {
         @UnsupportedAppUsage
         public boolean hasDefault;
@@ -8404,8 +8430,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;
@@ -8429,6 +8457,10 @@
         }
     }
 
+    /**
+     * @deprecated use {@link ComponentParseUtils.ParsedServiceIntentInfo}
+     */
+    @Deprecated
     public final static class ServiceIntentInfo extends IntentInfo {
         @UnsupportedAppUsage
         public Service service;
@@ -8452,6 +8484,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 249b691..b271ccd 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 70%
rename from core/java/android/content/pm/AndroidTestBaseUpdater.java
rename to core/java/android/content/pm/parsing/library/AndroidTestBaseUpdater.java
index da1a693..25c3099 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,12 +13,13 @@
  * 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.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;
@@ -38,23 +39,22 @@
 @VisibleForTesting
 public class AndroidTestBaseUpdater extends PackageSharedLibraryUpdater {
 
-    private static boolean apkTargetsApiLevelLessThanOrEqualToQ(Package pkg) {
-        int targetSdkVersion = pkg.applicationInfo.targetSdkVersion;
-        return targetSdkVersion <= Build.VERSION_CODES.Q;
+    private static boolean apkTargetsApiLevelLessThanOrEqualToQ(AndroidPackage pkg) {
+        return pkg.getTargetSdkVersion() <= Build.VERSION_CODES.Q;
     }
 
     @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.
-        if (apkTargetsApiLevelLessThanOrEqualToQ(pkg)) {
-            prefixRequiredLibrary(pkg, ANDROID_TEST_BASE);
+        if (apkTargetsApiLevelLessThanOrEqualToQ(parsedPackage)) {
+            prefixRequiredLibrary(parsedPackage, ANDROID_TEST_BASE);
         } else {
             // 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 fee8345..f04a671 100644
--- a/core/java/com/android/internal/content/NativeLibraryHelper.java
+++ b/core/java/com/android/internal/content/NativeLibraryHelper.java
@@ -28,12 +28,11 @@
 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.os.SystemProperties;
 import android.system.ErrnoException;
 import android.system.Os;
 import android.util.Slog;
@@ -88,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/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
index 61ea84f..86c709e0 100644
--- a/services/core/java/com/android/server/pm/AppsFilter.java
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -16,8 +16,6 @@
 
 package com.android.server.pm;
 
-import static android.content.pm.PackageParser.Component;
-import static android.content.pm.PackageParser.IntentInfo;
 import static android.provider.DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE;
 
 import android.Manifest;
@@ -25,8 +23,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.Build;
 import android.os.Process;
@@ -40,14 +41,15 @@
 
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ArrayUtils;
 import com.android.server.FgThread;
 import com.android.server.compat.PlatformCompat;
 
 import java.io.PrintWriter;
-import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
@@ -125,8 +127,7 @@
         boolean isGloballyEnabled();
 
         /** @return true if the feature is enabled for the given package. */
-        boolean packageIsEnabled(PackageParser.Package pkg);
-
+        boolean packageIsEnabled(AndroidPackage pkg);
     }
 
     private static class FeatureConfigImpl implements FeatureConfig {
@@ -159,14 +160,14 @@
         }
 
         @Override
-        public boolean packageIsEnabled(PackageParser.Package pkg) {
+        public boolean packageIsEnabled(AndroidPackage pkg) {
             final PlatformCompat compatibility = mInjector.getCompatibility();
             if (compatibility == null) {
                 Slog.wtf(TAG, "PlatformCompat is null");
                 return mFeatureEnabled;
             }
-            return compatibility.isChangeEnabled(
-                    PackageManager.FILTER_APPLICATION_QUERY, pkg.applicationInfo);
+            return compatibility.isChangeEnabled(PackageManager.FILTER_APPLICATION_QUERY,
+                    pkg.toAppInfo());
         }
     }
 
@@ -196,14 +197,13 @@
     }
 
     /** Returns true if the querying package may query for the potential target package */
-    private static boolean canQuery(PackageParser.Package querying,
-            PackageParser.Package potentialTarget) {
-        if (querying.mQueriesIntents == null) {
+    private static boolean canQuery(AndroidPackage querying, AndroidPackage potentialTarget) {
+        if (querying.getQueriesIntents() == null || potentialTarget.getActivities() == null) {
             return false;
         }
-        for (Intent intent : querying.mQueriesIntents) {
-            if (matches(intent, potentialTarget.providers, potentialTarget.activities,
-                    potentialTarget.services, potentialTarget.receivers)) {
+        for (Intent intent : querying.getQueriesIntents()) {
+            if (matches(intent, potentialTarget.getProviders(), potentialTarget.getActivities(),
+                    potentialTarget.getServices(), potentialTarget.getReceivers())) {
                 return true;
             }
         }
@@ -211,24 +211,24 @@
     }
 
     private static boolean matches(Intent intent,
-            ArrayList<PackageParser.Provider> providerList,
-            ArrayList<? extends Component<? extends IntentInfo>>... componentLists) {
-        for (int p = providerList.size() - 1; p >= 0; p--) {
-            PackageParser.Provider provider = providerList.get(p);
-            final ProviderInfo providerInfo = provider.info;
+            @Nullable List<ParsedProvider> providerList,
+            List<? extends ParsedComponent<? extends ParsedIntentInfo>>... componentLists) {
+        for (int p = ArrayUtils.size(providerList) - 1; p >= 0; p--) {
+            ParsedProvider provider = providerList.get(p);
             final Uri data = intent.getData();
             if ("content".equalsIgnoreCase(intent.getScheme())
                     && data != null
-                    && providerInfo.authority.equalsIgnoreCase(data.getAuthority())) {
+                    && provider.getAuthority().equalsIgnoreCase(data.getAuthority())) {
                 return true;
             }
         }
 
         for (int l = componentLists.length - 1; l >= 0; l--) {
-            ArrayList<? extends Component<? extends IntentInfo>> components = componentLists[l];
+            List<? extends ParsedComponent<? extends ParsedIntentInfo>> components =
+                    componentLists[l];
             for (int c = components.size() - 1; c >= 0; c--) {
-                Component<? extends IntentInfo> component = components.get(c);
-                ArrayList<? extends IntentInfo> intents = component.intents;
+                ParsedComponent<? extends ParsedIntentInfo> component = components.get(c);
+                List<? extends ParsedIntentInfo> intents = component.intents;
                 for (int i = intents.size() - 1; i >= 0; i--) {
                     IntentFilter intentFilter = intents.get(i);
                     if (intentFilter.match(intent.getAction(), intent.getType(), intent.getScheme(),
@@ -273,44 +273,44 @@
      * @param newPkg   the new package being added
      * @param existing all other packages currently on the device.
      */
-    public void addPackage(PackageParser.Package newPkg,
-            Map<String, PackageParser.Package> existing) {
+    public void addPackage(AndroidPackage newPkg, Map<String, AndroidPackage> existing) {
         // let's re-evaluate the ability of already added packages to see this new package
-        if (newPkg.mForceQueryable
+        if (newPkg.isForceQueryable()
                 || (mSystemAppsQueryable && (newPkg.isSystem() || newPkg.isUpdatedSystemApp()))) {
-            mForceQueryable.add(newPkg.packageName);
+            mForceQueryable.add(newPkg.getPackageName());
         } else {
             for (String packageName : mQueriesViaIntent.keySet()) {
-                if (packageName == newPkg.packageName) {
+                if (Objects.equals(packageName, newPkg.getPackageName())) {
                     continue;
                 }
-                final PackageParser.Package existingPackage = existing.get(packageName);
+                final AndroidPackage existingPackage = existing.get(packageName);
                 if (canQuery(existingPackage, newPkg)) {
-                    mQueriesViaIntent.get(packageName).add(newPkg.packageName);
+                    mQueriesViaIntent.get(packageName).add(newPkg.getPackageName());
                 }
             }
         }
         // if the new package declares them, let's evaluate its ability to see existing packages
-        mQueriesViaIntent.put(newPkg.packageName, new HashSet<>());
-        for (PackageParser.Package existingPackage : existing.values()) {
-            if (existingPackage.packageName == newPkg.packageName) {
+        mQueriesViaIntent.put(newPkg.getPackageName(), new HashSet<>());
+        for (AndroidPackage existingPackage : existing.values()) {
+            if (Objects.equals(existingPackage.getPackageName(), newPkg.getPackageName())) {
                 continue;
             }
-            if (existingPackage.mForceQueryable
+            if (existingPackage.isForceQueryable()
                     || (mSystemAppsQueryable
                     && (newPkg.isSystem() || newPkg.isUpdatedSystemApp()))) {
                 continue;
             }
             if (canQuery(newPkg, existingPackage)) {
-                mQueriesViaIntent.get(newPkg.packageName).add(existingPackage.packageName);
+                mQueriesViaIntent.get(newPkg.getPackageName())
+                        .add(existingPackage.getPackageName());
             }
         }
         final HashSet<String> queriesPackages = new HashSet<>(
-                newPkg.mQueriesPackages == null ? 0 : newPkg.mQueriesPackages.size());
-        if (newPkg.mQueriesPackages != null) {
-            queriesPackages.addAll(newPkg.mQueriesPackages);
+                newPkg.getQueriesPackages() == null ? 0 : newPkg.getQueriesPackages().size());
+        if (newPkg.getQueriesPackages() != null) {
+            queriesPackages.addAll(newPkg.getQueriesPackages());
         }
-        mQueriesViaPackage.put(newPkg.packageName, queriesPackages);
+        mQueriesViaPackage.put(newPkg.getPackageName(), queriesPackages);
     }
 
     /**
@@ -405,8 +405,8 @@
 
     private boolean shouldFilterApplicationInternal(
             PackageSetting callingPkgSetting, PackageSetting targetPkgSetting, int userId) {
-        final String callingName = callingPkgSetting.pkg.packageName;
-        final PackageParser.Package targetPkg = targetPkgSetting.pkg;
+        final String callingName = callingPkgSetting.pkg.getPackageName();
+        final AndroidPackage targetPkg = targetPkgSetting.pkg;
 
         if (!mFeatureConfig.packageIsEnabled(callingPkgSetting.pkg)) {
             if (DEBUG_LOGGING) {
@@ -422,8 +422,8 @@
             }
             return true;
         }
-        final String targetName = targetPkg.packageName;
-        if (callingPkgSetting.pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.R) {
+        final String targetName = targetPkg.getPackageName();
+        if (callingPkgSetting.pkg.getTargetSdkVersion() < Build.VERSION_CODES.R) {
             if (DEBUG_LOGGING) {
                 log(callingPkgSetting, targetPkgSetting, "caller pre-R");
             }
@@ -435,7 +435,7 @@
             }
             return false;
         }
-        if (targetPkg.mForceQueryable) {
+        if (targetPkg.isForceQueryable()) {
             if (DEBUG_LOGGING) {
                 log(callingPkgSetting, targetPkgSetting, "manifest forceQueryable");
             }
@@ -470,9 +470,11 @@
             }
             return false;
         }
-        if (callingPkgSetting.pkg.instrumentation.size() > 0) {
-            for (int i = 0, max = callingPkgSetting.pkg.instrumentation.size(); i < max; i++) {
-                if (callingPkgSetting.pkg.instrumentation.get(i).info.targetPackage == targetName) {
+        List<ComponentParseUtils.ParsedInstrumentation> instrumentations =
+                callingPkgSetting.pkg.getInstrumentations();
+        if (ArrayUtils.size(instrumentations) > 0) {
+            for (int i = 0, max = instrumentations.size(); i < max; i++) {
+                if (Objects.equals(instrumentations.get(i).getTargetPackage(), targetName)) {
                     if (DEBUG_LOGGING) {
                         log(callingPkgSetting, targetPkgSetting, "instrumentation");
                     }
@@ -504,7 +506,7 @@
 
     private boolean isImplicitlyQueryableSystemApp(PackageSetting targetPkgSetting) {
         return targetPkgSetting.isSystem() && (mSystemAppsQueryable
-                || mForceQueryableByDevice.contains(targetPkgSetting.pkg.packageName));
+                || mForceQueryableByDevice.contains(targetPkgSetting.pkg.getPackageName()));
     }
 
     public void dumpQueries(
diff --git a/services/core/java/com/android/server/pm/ComponentResolver.java b/services/core/java/com/android/server/pm/ComponentResolver.java
index 8facce1..333a6e9 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.content.ComponentName;
 import android.content.Intent;
@@ -32,13 +31,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;
@@ -49,15 +53,19 @@
 import android.util.Slog;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.ArrayUtils;
 import com.android.server.IntentResolver;
 
 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 {
@@ -158,7 +166,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")
@@ -166,7 +174,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;
@@ -181,7 +189,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,
@@ -192,28 +200,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);
         }
@@ -226,7 +234,7 @@
     }
 
     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);
@@ -240,7 +248,7 @@
     }
 
     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);
         }
@@ -254,25 +262,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;
                 }
@@ -285,17 +302,23 @@
         return providerList;
     }
 
-    ProviderInfo queryProvider(String authority, int flags, int userId) {
+    ProviderInfo queryProvider(String authority, int flags, int uid, 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);
         }
     }
 
@@ -303,20 +326,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;
                 }
@@ -333,7 +365,7 @@
     }
 
     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);
         }
@@ -346,7 +378,7 @@
     }
 
     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);
         }
@@ -360,15 +392,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);
@@ -378,17 +410,19 @@
         final String setupWizardPackage = sPackageManagerInternal.getKnownPackageName(
                 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);
         }
@@ -407,7 +441,7 @@
         if (mProtectedFilters == null || mProtectedFilters.size() == 0) {
             return;
         }
-        final List<ActivityIntentInfo> protectedFilters = mProtectedFilters;
+        final List<ParsedActivityIntentInfo> protectedFilters = mProtectedFilters;
         mProtectedFilters = null;
 
         final String setupWizardPackage = sPackageManagerInternal.getKnownPackageName(
@@ -417,13 +451,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
@@ -431,8 +465,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);
@@ -473,8 +507,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) {
@@ -484,14 +518,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) {
@@ -503,25 +540,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);
             }
@@ -529,14 +584,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) {
@@ -544,7 +597,7 @@
                 } else {
                     r.append(' ');
                 }
-                r.append(a.info.name);
+                r.append(a.getName());
             }
         }
         if (DEBUG_PACKAGE_SCANNING && chatty) {
@@ -553,20 +606,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
@@ -574,23 +624,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)
@@ -598,7 +648,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);
                     }
                 }
@@ -609,7 +659,7 @@
                 } else {
                     r.append(' ');
                 }
-                r.append(p.info.name);
+                r.append(p.getName());
             }
         }
         if (DEBUG_PACKAGE_SCANNING && chatty) {
@@ -618,13 +668,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) {
@@ -632,7 +680,7 @@
                 } else {
                     r.append(' ');
                 }
-                r.append(a.info.name);
+                r.append(a.getName());
             }
         }
         if (DEBUG_PACKAGE_SCANNING && chatty) {
@@ -641,13 +689,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) {
@@ -655,7 +701,7 @@
                 } else {
                     r.append(' ');
                 }
-                r.append(s.info.name);
+                r.append(s.getName());
             }
         }
         if (DEBUG_PACKAGE_SCANNING && chatty) {
@@ -663,13 +709,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
@@ -680,14 +725,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)) {
@@ -705,7 +750,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();
@@ -719,20 +764,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;
                 }
             }
@@ -753,24 +798,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);
@@ -794,8 +838,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;
@@ -804,12 +848,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
@@ -817,8 +861,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);
@@ -830,14 +874,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);
@@ -847,19 +905,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);
@@ -870,13 +928,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);
@@ -887,13 +946,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);
@@ -905,14 +964,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);
@@ -929,8 +988,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);
@@ -940,15 +999,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) {
@@ -956,32 +1015,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());
                     }
                 }
             }
@@ -991,17 +1050,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) {
@@ -1009,17 +1068,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) {
@@ -1027,7 +1086,7 @@
                 } else {
                     r.append(' ');
                 }
-                r.append(s.info.name);
+                r.append(s.getName());
             }
         }
         if (DEBUG_REMOVE && chatty) {
@@ -1036,26 +1095,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);
                         }
                     }
@@ -1064,8 +1123,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) {
@@ -1086,24 +1146,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);
                 }
@@ -1111,21 +1171,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);
                 }
@@ -1134,23 +1194,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), "      ");
@@ -1161,11 +1221,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;
                 }
             }
@@ -1173,34 +1233,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: "
@@ -1210,7 +1275,7 @@
         }
 
         @Override
-        protected ResolveInfo newResult(PackageParser.ActivityIntentInfo info,
+        protected ResolveInfo newResult(ParsedActivityIntentInfo info,
                 int match, int userId) {
             if (!sUserManager.exists(userId)) {
                 if (DEBUG) {
@@ -1218,7 +1283,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),
@@ -1226,8 +1313,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);
@@ -1236,10 +1323,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;
@@ -1289,7 +1376,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;
@@ -1314,40 +1401,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) {
@@ -1367,24 +1478,24 @@
         }
 
         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);
                 }
@@ -1392,7 +1503,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;
@@ -1401,39 +1512,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), "      ");
@@ -1444,12 +1555,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;
                 }
             }
@@ -1457,47 +1567,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;
             }
@@ -1507,7 +1638,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
@@ -1519,8 +1650,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;
             }
@@ -1529,13 +1660,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;
         }
@@ -1547,26 +1678,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);
@@ -1575,12 +1717,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) {
@@ -1598,22 +1740,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);
                 }
@@ -1621,40 +1763,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), "      ");
@@ -1665,12 +1807,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;
                 }
             }
@@ -1678,48 +1819,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;
@@ -1729,7 +1891,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
@@ -1746,13 +1908,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;
         }
@@ -1764,31 +1926,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)");
             }
@@ -1796,7 +1969,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;
     }
 
@@ -1885,7 +2058,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;
         }
     }
@@ -1893,7 +2066,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();
         }
     }
@@ -1901,7 +2074,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();
         }
     }
@@ -1909,7 +2082,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();
         }
     }
@@ -1917,9 +2090,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 3464cab..c844f1b 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;
@@ -445,7 +445,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;
@@ -456,8 +456,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 1d3d24c..6de5203 100644
--- a/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
+++ b/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
@@ -28,7 +28,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;
@@ -122,10 +122,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,
@@ -192,12 +192,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;
     }
@@ -210,8 +210,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;
@@ -263,7 +263,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.");
             }
@@ -284,14 +284,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()) {
@@ -318,12 +318,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.");
                 }
@@ -382,7 +383,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 {
@@ -449,9 +450,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()));
     }
 
     /**
@@ -470,11 +471,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;
@@ -483,7 +484,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) {
@@ -521,7 +522,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 b720290..a34ca91 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;
@@ -1573,7 +1574,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);
@@ -1672,7 +1673,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 d07e2d2..f706dc3 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;
@@ -158,7 +157,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;
@@ -169,7 +167,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;
@@ -194,6 +191,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;
@@ -460,20 +470,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,
@@ -484,7 +493,6 @@
             SCAN_REQUIRE_KNOWN,
             SCAN_MOVE,
             SCAN_INITIAL,
-            SCAN_CHECK_ONLY,
             SCAN_DONT_KILL_APP,
             SCAN_IGNORE_FROZEN,
             SCAN_FIRST_BOOT_OR_UPGRADE,
@@ -603,11 +611,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 =
@@ -664,7 +680,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.
@@ -977,17 +993,17 @@
             return PackageManagerService.this.hasSystemFeature(feature, 0);
         }
 
-        final List<PackageParser.Package> getStaticOverlayPackages(
-                Collection<PackageParser.Package> allPackages, String targetPackageName) {
+        final List<AndroidPackage> getStaticOverlayPackages(
+                Collection<AndroidPackage> allPackages, String targetPackageName) {
             if ("android".equals(targetPackageName)) {
                 // Static RROs targeting to "android", ie framework-res.apk, are already applied by
                 // native AssetManager.
                 return null;
             }
 
-            List<PackageParser.Package> overlayPackages = null;
-            for (PackageParser.Package p : allPackages) {
-                if (targetPackageName.equals(p.mOverlayTarget) && p.mOverlayIsStatic) {
+            List<AndroidPackage> overlayPackages = null;
+            for (AndroidPackage p : allPackages) {
+                if (targetPackageName.equals(p.getOverlayTarget()) && p.isOverlayIsStatic()) {
                     if (overlayPackages == null) {
                         overlayPackages = new ArrayList<>();
                     }
@@ -995,25 +1011,25 @@
                 }
             }
             if (overlayPackages != null) {
-                Comparator<PackageParser.Package> cmp =
-                        Comparator.comparingInt(p -> p.mOverlayPriority);
+                Comparator<AndroidPackage> cmp =
+                        Comparator.comparingInt(p -> p.getOverlayPriority());
                 overlayPackages.sort(cmp);
             }
             return overlayPackages;
         }
 
-        final String[] getStaticOverlayPaths(List<PackageParser.Package> overlayPackages,
+        final String[] getStaticOverlayPaths(List<AndroidPackage> overlayPackages,
                 String targetPath) {
             if (overlayPackages == null || overlayPackages.isEmpty()) {
                 return null;
             }
             List<String> overlayPathList = null;
-            for (PackageParser.Package overlayPackage : overlayPackages) {
+            for (AndroidPackage overlayPackage : overlayPackages) {
                 if (targetPath == null) {
                     if (overlayPathList == null) {
                         overlayPathList = new ArrayList<>();
                     }
-                    overlayPathList.add(overlayPackage.baseCodePath);
+                    overlayPathList.add(overlayPackage.getBaseCodePath());
                     continue;
                 }
 
@@ -1023,23 +1039,23 @@
                     //
                     // OverlayManagerService will update each of them with a correct gid from its
                     // target package app id.
-                    mInstaller.idmap(targetPath, overlayPackage.baseCodePath,
+                    mInstaller.idmap(targetPath, overlayPackage.getBaseCodePath(),
                             UserHandle.getSharedAppGid(
                                     UserHandle.getUserGid(UserHandle.USER_SYSTEM)));
                     if (overlayPathList == null) {
                         overlayPathList = new ArrayList<>();
                     }
-                    overlayPathList.add(overlayPackage.baseCodePath);
+                    overlayPathList.add(overlayPackage.getBaseCodePath());
                 } catch (InstallerException e) {
                     Slog.e(TAG, "Failed to generate idmap for " + targetPath + " and " +
-                            overlayPackage.baseCodePath);
+                            overlayPackage.getBaseCodePath());
                 }
             }
             return overlayPathList == null ? null : overlayPathList.toArray(new String[0]);
         }
 
         String[] getStaticOverlayPaths(String targetPackageName, String targetPath) {
-            List<PackageParser.Package> overlayPackages;
+            List<AndroidPackage> overlayPackages;
             synchronized (mInstallLock) {
                 synchronized (mLock) {
                     overlayPackages = getStaticOverlayPackages(
@@ -1062,12 +1078,12 @@
     }
 
     class ParallelPackageParserCallback extends PackageParserCallback {
-        List<PackageParser.Package> mOverlayPackages = null;
+        List<AndroidPackage> mOverlayPackages = null;
 
         void findStaticOverlayPackages() {
             synchronized (mLock) {
-                for (PackageParser.Package p : mPackages.values()) {
-                    if (p.mOverlayIsStatic) {
+                for (AndroidPackage p : mPackages.values()) {
+                    if (p.isOverlayIsStatic()) {
                         if (mOverlayPackages == null) {
                             mOverlayPackages = new ArrayList<>();
                         }
@@ -1101,7 +1117,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
@@ -1150,13 +1166,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;
 
@@ -1189,14 +1205,19 @@
     private Future<?> mPrepareAppDataFuture;
 
     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;
@@ -1210,7 +1231,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<>();
@@ -1235,11 +1256,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) {
@@ -1291,14 +1312,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()
@@ -1411,7 +1432,7 @@
 
         @Override
         public boolean addOneIntentFilterVerification(int verifierUid, int userId, int verificationId,
-                    ActivityIntentInfo filter, String packageName) {
+                ParsedActivityIntentInfo filter, String packageName) {
             if (!hasValidDomains(filter)) {
                 return false;
             }
@@ -1440,7 +1461,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));
@@ -1705,7 +1726,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
@@ -1851,8 +1872,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: {
@@ -2002,20 +2023,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.
@@ -2024,7 +2036,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) {
@@ -2058,13 +2070,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);
 
@@ -2142,30 +2155,30 @@
                         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 /*killFlag*/,
-                            new ArrayList<>(Collections.singletonList(pkg.packageName)),
-                            pkg.applicationInfo.uid);
+                    sendPackageChangedBroadcast(pkg.getPackageName(), false /*killFlag*/,
+                            new ArrayList<>(Collections.singletonList(pkg.getPackageName())),
+                            pkg.getUid());
                 }
             }
 
@@ -2295,7 +2308,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);
@@ -2833,11 +2846,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());
                     }
                 }
 
@@ -2856,7 +2869,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
@@ -2933,7 +2946,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
@@ -2959,7 +2972,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: "
@@ -3154,7 +3167,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)) {
@@ -3254,12 +3267,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;
                     }
@@ -3346,7 +3359,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;
@@ -3390,43 +3403,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");
@@ -3438,31 +3454,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;
@@ -3545,18 +3563,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/.
@@ -3568,10 +3588,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)) {
@@ -3895,7 +3917,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>");
@@ -3903,13 +3925,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());
                         }
                     }
                 }
@@ -4025,7 +4049,7 @@
         }
 
         final PackageUserState state = ps.readUserState(userId);
-        PackageParser.Package p = ps.pkg;
+        AndroidPackage p = ps.pkg;
         if (p != null) {
             final PermissionsState permissionsState = ps.getPermissionsState();
 
@@ -4033,10 +4057,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) {
@@ -4099,7 +4123,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!");
             }
         }
@@ -4112,9 +4136,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;
                 }
@@ -4179,21 +4203,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);
@@ -4229,34 +4254,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);
@@ -4300,16 +4325,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
@@ -4358,12 +4383,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;
         }
@@ -4385,7 +4410,8 @@
                 if (index < 0) {
                     continue;
                 }
-                if (uidPs.pkg.usesStaticLibrariesVersions[index] == libraryInfo.getLongVersion()) {
+                if (uidPs.pkg.getUsesStaticLibrariesVersions()[index]
+                        == libraryInfo.getLongVersion()) {
                     return false;
                 }
             }
@@ -4459,13 +4485,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);
@@ -4489,9 +4515,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;
                 }
@@ -4541,7 +4567,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);
@@ -4579,7 +4605,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);
@@ -4593,7 +4619,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);
@@ -4969,17 +4995,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)) {
@@ -5016,7 +5044,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;
             }
@@ -5046,17 +5074,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);
             }
         }
@@ -5235,13 +5273,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<>();
                     }
@@ -5261,17 +5299,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);
             }
         }
@@ -5286,18 +5329,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;
@@ -5555,21 +5607,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);
         }
     }
 
@@ -5632,21 +5684,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;
             }
@@ -5699,16 +5751,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) {
@@ -5727,24 +5779,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;
@@ -6590,7 +6641,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;
@@ -6662,9 +6713,11 @@
                     list.add(ri);
                 }
             }
-            return applyPostResolutionFilter(
+
+            List<ResolveInfo> result = applyPostResolutionFilter(
                     list, instantAppPkgName, allowDynamicSplits, filterCallingUid, resolveForStart,
                     userId, intent);
+            return result;
         }
 
         // reader
@@ -6741,11 +6794,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
@@ -7638,10 +7691,10 @@
                         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);
+                        intent, resolvedType, flags, pkg.getReceivers(), userId);
                 return applyPostResolutionFilter(
                         result, instantAppPkgName, allowDynamicSplits, callingUid, false, userId,
                         intent);
@@ -7740,11 +7793,11 @@
                         mComponentResolver.queryServices(intent, resolvedType, flags, userId),
                         instantAppPkgName);
             }
-            final PackageParser.Package pkg = mPackages.get(pkgName);
+            final AndroidPackage pkg = mPackages.get(pkgName);
             if (pkg != null) {
                 return applyPostServiceResolutionFilter(
-                        mComponentResolver.queryServices(intent, resolvedType, flags, pkg.services,
-                                userId),
+                        mComponentResolver.queryServices(intent, resolvedType, flags,
+                                pkg.getServices(), userId),
                         instantAppPkgName);
             }
             return Collections.emptyList();
@@ -7858,11 +7911,11 @@
                         mComponentResolver.queryProviders(intent, resolvedType, flags, userId),
                         instantAppPkgName);
             }
-            final PackageParser.Package pkg = mPackages.get(pkgName);
+            final AndroidPackage pkg = mPackages.get(pkgName);
             if (pkg != null) {
                 return applyPostContentProviderResolutionFilter(
                         mComponentResolver.queryProviders(intent, resolvedType, flags,
-                                pkg.providers, userId),
+                                pkg.getProviders(), userId),
                         instantAppPkgName);
             }
             return Collections.emptyList();
@@ -7947,16 +8000,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);
                     }
@@ -8035,8 +8087,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);
@@ -8089,7 +8141,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);
@@ -8106,16 +8158,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);
@@ -8171,7 +8223,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)
@@ -8242,9 +8293,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
@@ -8260,23 +8311,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);
@@ -8298,7 +8348,8 @@
         if (!mUserManager.exists(userId)) return null;
         flags = updateFlagsForComponent(flags, userId, name);
         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;
         }
@@ -8380,8 +8431,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);
         }
     }
 
@@ -8403,12 +8454,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);
@@ -8465,18 +8516,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());
@@ -8500,15 +8551,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)) {
@@ -8518,21 +8570,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 {
@@ -8546,20 +8598,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());
         }
     }
 
@@ -8568,7 +8620,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 {
@@ -8583,7 +8635,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();
@@ -8593,9 +8645,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 {
@@ -8603,66 +8655,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;
                 }
             }
@@ -8711,7 +8722,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 {
@@ -8727,25 +8738,27 @@
         // 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;
+            final String disabledPkgName =
+                    pkgAlreadyExists ? pkgSetting.name : parsedPackage.getPackageName();
             disabledPkgSetting = mSettings.getDisabledSystemPkgLPr(disabledPkgName);
             isSystemPkgUpdated = disabledPkgSetting != null;
 
@@ -8753,49 +8766,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) {
@@ -8806,9 +8799,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) {
@@ -8824,12 +8817,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);
@@ -8840,9 +8834,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
@@ -8853,18 +8848,18 @@
         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
         // in verified partition, or can be verified on access (when apk verity is enabled). In both
         // cases, only data in Signing Block is verified instead of the whole file.
         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
@@ -8876,17 +8871,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) {
@@ -8895,12 +8893,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();
                 }
@@ -8911,13 +8912,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) {
@@ -8930,7 +8933,7 @@
                                     mSharedLibraries,
                                     mPackages,
                                     Collections.singletonMap(
-                                            pkgName, getSettingsVersionForPackage(pkg)),
+                                            pkgName, getSettingsVersionForPackage(parsedPackage)),
                                     Collections.singletonMap(pkgName,
                                             getSharedLibLatestVersionSetting(scanResult))),
                             mSettings.mKeySetManagerService);
@@ -8947,16 +8950,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) {
@@ -9057,7 +9061,7 @@
             return;
         }
 
-        List<PackageParser.Package> pkgs;
+        List<AndroidPackage> pkgs;
         synchronized (mLock) {
             pkgs = PackageManagerServiceUtils.getPackagesForDexopt(mPackages.values(), this);
         }
@@ -9080,8 +9084,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";
     }
 
     /**
@@ -9090,7 +9094,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;
@@ -9099,7 +9103,7 @@
         int numberOfPackagesFailed = 0;
         final int numberOfPackagesToDexopt = pkgs.size();
 
-        for (PackageParser.Package pkg : pkgs) {
+        for (AndroidPackage pkg : pkgs) {
             numberOfPackagesVisited++;
 
             boolean useProfileForDexopt = false;
@@ -9115,7 +9119,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 {
@@ -9128,11 +9132,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 =
@@ -9151,7 +9156,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 {
@@ -9168,7 +9173,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;
@@ -9176,7 +9181,7 @@
 
             if (DEBUG_DEXOPT) {
                 Log.i(TAG, "Updating app " + numberOfPackagesVisited + " of " +
-                        numberOfPackagesToDexopt + ": " + pkg.packageName);
+                        numberOfPackagesToDexopt + ": " + pkg.getPackageName());
             }
 
             if (showDialog) {
@@ -9213,7 +9218,7 @@
                 dexoptFlags |= DexoptOptions.DEXOPT_INSTALL_WITH_DEX_METADATA_FILE;
             }
             int primaryDexOptStaus = performDexOptTraced(new DexoptOptions(
-                    pkg.packageName,
+                    pkg.getPackageName(),
                     pkgCompilationReason,
                     dexoptFlags));
 
@@ -9257,11 +9262,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
@@ -9341,7 +9346,7 @@
     */
     @Override
     public boolean compileLayouts(String packageName) {
-        PackageParser.Package pkg;
+        AndroidPackage pkg;
         synchronized (mLock) {
             pkg = mPackages.get(packageName);
             if (pkg == null) {
@@ -9388,7 +9393,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) {
@@ -9411,16 +9416,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
@@ -9437,14 +9442,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());
                 }
@@ -9452,7 +9458,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.
@@ -9461,7 +9467,7 @@
         }
         return pdo.performDexOpt(p, instructionSets,
                 getOrCreateCompilerPackageStats(p),
-                mDexManager.getPackageUseInfoOrDefault(p.packageName), options);
+                mDexManager.getPackageUseInfoOrDefault(p.getPackageName()), options);
     }
 
     /**
@@ -9502,11 +9508,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;
@@ -9529,13 +9535,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);
                     }
@@ -9573,9 +9579,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;
         }
@@ -9583,7 +9589,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);
             }
         }
@@ -9599,7 +9605,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());
@@ -9628,7 +9634,7 @@
 
     @Override
     public void dumpProfiles(String packageName) {
-        PackageParser.Package pkg;
+        AndroidPackage pkg;
         synchronized (mLock) {
             pkg = mPackages.get(packageName);
             if (pkg == null) {
@@ -9639,7 +9645,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");
         }
 
@@ -9654,7 +9660,7 @@
     public void forceDexOpt(String packageName) {
         enforceSystemOrRoot("forceDexOpt");
 
-        PackageParser.Package pkg;
+        AndroidPackage pkg;
         synchronized (mLock) {
             pkg = mPackages.get(packageName);
             if (pkg == null) {
@@ -9681,15 +9687,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;
         }
@@ -9713,122 +9719,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
@@ -9837,14 +9807,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) {
@@ -9856,19 +9826,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;
             }
         }
@@ -9878,23 +9848,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 {
@@ -9905,44 +9875,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);
         }
     }
 
@@ -9952,7 +9923,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 {
@@ -9981,8 +9952,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"
@@ -9993,9 +9964,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
@@ -10025,7 +9996,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" +
@@ -10057,28 +10028,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) {
@@ -10090,8 +10061,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);
                     }
                 }
@@ -10106,8 +10077,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());
                 }
@@ -10117,43 +10089,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. */
@@ -10200,9 +10144,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;
         /**
@@ -10226,9 +10170,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,
@@ -10237,7 +10181,7 @@
                 @ScanFlags int scanFlags,
                 boolean isPlatformPackage,
                 @Nullable UserHandle user) {
-            this.pkg = pkg;
+            this.parsedPackage = parsedPackage;
             this.oldPkg = oldPkg;
             this.pkgSetting = pkgSetting;
             this.sharedUserSetting = sharedUserSetting;
@@ -10270,7 +10214,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.
@@ -10322,12 +10266,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
@@ -10336,7 +10282,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;
                     }
                 }
@@ -10351,46 +10298,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);
         }
     }
@@ -10433,11 +10384,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;
@@ -10454,13 +10412,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);
             }
         }
@@ -10473,12 +10429,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) {
@@ -10487,7 +10444,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;
@@ -10495,17 +10452,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());
                     }
                 }
             }
@@ -10522,21 +10479,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;
     }
 
     /**
@@ -10544,18 +10495,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);
     }
 
     /**
@@ -10566,14 +10518,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?
@@ -10581,18 +10533,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;
             }
@@ -10605,19 +10557,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
@@ -10625,22 +10577,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
@@ -10680,7 +10630,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;
@@ -10695,13 +10645,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.
@@ -10720,7 +10669,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 "
@@ -10730,30 +10679,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.
             //
@@ -10761,18 +10708,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
@@ -10791,7 +10738,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);
         }
 
         // Apps which share a sharedUserId must be placed in the same selinux domain. If this
@@ -10803,68 +10750,72 @@
         // will NOT be modified until next boot, even if a lower targetSdkVersion is used. This
         // ensures that all packages continue to run in the same selinux domain.
         final int targetSdkVersion =
-            ((sharedUserSetting != null) && (sharedUserSetting.packages.size() != 0)) ?
-            sharedUserSetting.seInfoTargetSdkVersion : pkg.applicationInfo.targetSdkVersion;
+                ((sharedUserSetting != null) && (sharedUserSetting.packages.size() != 0)) ?
+                        sharedUserSetting.seInfoTargetSdkVersion
+                        : parsedPackage.getTargetSdkVersion();
         // TODO(b/71593002): isPrivileged for sharedUser and appInfo should never be out of sync.
         // They currently can be if the sharedUser apps are signed with the platform key.
         final boolean isPrivileged = (sharedUserSetting != null) ?
-            sharedUserSetting.isPrivileged() | pkg.isPrivileged() : pkg.isPrivileged();
+                sharedUserSetting.isPrivileged() | parsedPackage.isPrivileged()
+                : parsedPackage.isPrivileged();
 
-        pkg.applicationInfo.seInfo = SELinuxMMAC.getSeInfo(pkg, isPrivileged,
-                targetSdkVersion);
-        pkg.applicationInfo.seInfoUser = SELinuxUtil.assignSeinfoUser(pkgSetting.readUserState(
-                userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : userId));
-
-        pkg.mExtras = pkgSetting;
-        pkg.applicationInfo.processName = fixProcessName(
-                pkg.applicationInfo.packageName,
-                pkg.applicationInfo.processName);
+        parsedPackage.setSeInfo(
+                SELinuxMMAC.getSeInfo(parsedPackage, isPrivileged, targetSdkVersion))
+                .setSeInfoUser(
+                        SELinuxUtil.assignSeinfoUser(pkgSetting.readUserState(
+                                userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : userId)))
+                .setProcessName(fixProcessName(
+                        parsedPackage.getPackageName(),
+                        parsedPackage.getProcessName()));
 
         if (!isPlatformPackage) {
             // Get all of our default paths setup
-            pkg.applicationInfo.initForUser(UserHandle.USER_SYSTEM);
+            parsedPackage.initForUser(UserHandle.USER_SYSTEM);
         }
 
-        final String cpuAbiOverride = deriveAbiOverride(pkg.cpuAbiOverride, pkgSetting);
+        final String cpuAbiOverride = deriveAbiOverride(parsedPackage.getCpuAbiOverride(),
+                pkgSetting);
 
         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 {
@@ -10872,8 +10823,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
@@ -10881,8 +10832,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
@@ -10890,8 +10841,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
@@ -10899,34 +10850,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) {
@@ -10936,22 +10887,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)) {
+        if (isSystemApp(parsedPackage)) {
             pkgSetting.isOrphaned = 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;
@@ -10969,32 +10918,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));
             }
         }
 
@@ -11030,22 +10980,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");
                 }
             }
         }
@@ -11058,118 +11007,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)
@@ -11189,15 +11079,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");
@@ -11208,9 +11098,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
@@ -11219,11 +11110,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.");
@@ -11231,23 +11122,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");
                 }
@@ -11260,73 +11152,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");
                 }
@@ -11336,16 +11222,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;
@@ -11360,23 +11247,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
@@ -11386,29 +11256,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.");
                     }
                 }
@@ -11423,11 +11294,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");
@@ -11435,18 +11308,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
@@ -11454,54 +11327,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");
                         }
@@ -11511,18 +11392,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>");
                             }
@@ -11602,71 +11484,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);
                 }
             }
         }
@@ -11690,9 +11568,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");
             }
         }
 
@@ -11705,7 +11583,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;
@@ -11716,7 +11594,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);
@@ -11724,31 +11602,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) {
@@ -11756,19 +11634,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());
                 }
             }
 
@@ -11792,14 +11667,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;
@@ -11866,22 +11741,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");
         }
     }
 
@@ -11893,45 +11759,23 @@
 
         // writer
         synchronized (mLock) {
-            final PackageParser.Package removedPackage = mPackages.remove(packageName);
+            final AndroidPackage removedPackage = mPackages.remove(packageName);
             if (removedPackage != null) {
                 cleanPackageDataStructuresLILPw(removedPackage, chatty);
             }
         }
     }
 
-    void removeInstalledPackageLI(PackageParser.Package pkg, boolean chatty) {
-        if (DEBUG_INSTALL) {
-            if (chatty)
-                Log.d(TAG, "Removing package " + pkg.applicationInfo.packageName);
-        }
-
-        // writer
-        synchronized (mLock) {
-            // Remove the parent package
-            mPackages.remove(pkg.applicationInfo.packageName);
-            cleanPackageDataStructuresLILPw(pkg, chatty);
-
-            // Remove 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);
-                mPackages.remove(childPkg.applicationInfo.packageName);
-                cleanPackageDataStructuresLILPw(childPkg, chatty);
-            }
-        }
-    }
-
-    void cleanPackageDataStructuresLILPw(PackageParser.Package pkg, boolean chatty) {
+    void cleanPackageDataStructuresLILPw(AndroidPackage pkg, boolean chatty) {
         mComponentResolver.removeAllComponents(pkg, chatty);
-        mAppsFilter.removePackage(pkg.packageName);
+        mAppsFilter.removePackage(pkg.getPackageName());
         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) {
@@ -11939,7 +11783,7 @@
                 } else {
                     r.append(' ');
                 }
-                r.append(a.info.name);
+                r.append(a.getName());
             }
         }
         if (r != null) {
@@ -11947,12 +11791,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) {
@@ -11970,15 +11814,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());
                 }
             }
         }
@@ -12319,11 +12164,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.
@@ -12369,17 +12214,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);
             }
         }
     }
@@ -12575,7 +12420,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);
@@ -13012,11 +12857,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;
                     }
                 }
@@ -13161,10 +13006,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;
@@ -13178,7 +13023,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) {
@@ -13193,7 +13038,7 @@
                 return -1;
             }
 
-            return pkg.applicationInfo.uid;
+            return pkg.getUid();
         }
     }
 
@@ -13381,26 +13226,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);
+                }
+            };
         }
     }
 
@@ -13581,7 +13433,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);
 
@@ -13619,7 +13471,7 @@
                 try {
                     if (bm.isBackupServiceActive(userId)) {
                         bm.restoreAtInstallForUser(
-                                userId, res.pkg.applicationInfo.packageName, token);
+                                userId, res.pkg.getAppInfoPackageName(), token);
                     } else {
                         doRestore = false;
                     }
@@ -13644,8 +13496,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;
 
@@ -13714,7 +13566,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]) {
@@ -14056,12 +13908,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) {
@@ -14088,7 +13940,7 @@
 
                 if (dataOwnerPkg != null) {
                     if (!PackageManagerServiceUtils.isDowngradePermitted(installFlags,
-                            dataOwnerPkg.applicationInfo.flags)) {
+                            dataOwnerPkg.getFlags())) {
                         try {
                             checkDowngrade(dataOwnerPkg, pkgLite);
                         } catch (PackageManagerException e) {
@@ -14101,7 +13953,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
@@ -14564,7 +14416,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 */
@@ -14712,7 +14564,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;
@@ -14720,7 +14573,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);
             try {
@@ -14741,24 +14594,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;
         }
@@ -14861,20 +14713,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;
         }
@@ -14950,14 +14802,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);
@@ -15013,123 +14865,39 @@
         }
     }
 
-    /**
-     * 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")
-    private boolean disableSystemPackageLPw(PackageParser.Package oldPkg,
-            PackageParser.Package newPkg) {
-        // Disable the parent package (parent always replaced)
-        boolean disabled = mSettings.disableSystemPackageLPw(oldPkg.packageName, true);
-        // Disable the child packages
-        final int childCount = (oldPkg.childPackages != null) ? oldPkg.childPackages.size() : 0;
-        for (int i = 0; i < childCount; i++) {
-            PackageParser.Package childPkg = oldPkg.childPackages.get(i);
-            final boolean replace = newPkg.hasChildPackage(childPkg.packageName);
-            disabled |= mSettings.disableSystemPackageLPw(childPkg.packageName, replace);
-        }
-        return disabled;
+    private boolean disableSystemPackageLPw(AndroidPackage oldPkg) {
+        return mSettings.disableSystemPackageLPw(oldPkg.getPackageName(), true);
     }
 
-    @GuardedBy("mLock")
-    private void setInstallerPackageNameLPw(PackageParser.Package pkg,
-            String installerPackageName) {
-        // Enable the parent package
-        mSettings.setInstallerPackageName(pkg.packageName, installerPackageName);
-        // 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.setInstallerPackageName(childPkg.packageName, installerPackageName);
-        }
-    }
-
-    private void updateSettingsLI(PackageParser.Package newPackage, String installerPackageName,
+    private void updateSettingsLI(AndroidPackage newPackage, String installerPackageName,
             int[] allUsers, PackageInstalledInfo res, UserHandle user, int installReason) {
-        // Update the parent package setting
         updateSettingsInternalLI(newPackage, installerPackageName, allUsers, res.origUsers,
                 res, user, installReason);
-        // Update the child packages setting
-        final int childCount = (newPackage.childPackages != null)
-                ? newPackage.childPackages.size() : 0;
-        for (int i = 0; i < childCount; i++) {
-            PackageParser.Package childPackage = newPackage.childPackages.get(i);
-            PackageInstalledInfo childRes = res.addedChildPackages.get(childPackage.packageName);
-            updateSettingsInternalLI(childPackage, installerPackageName, allUsers,
-                    childRes.origUsers, childRes, user, installReason);
-        }
     }
 
-    private void updateSettingsInternalLI(PackageParser.Package pkg,
+    private void updateSettingsInternalLI(AndroidPackage pkg,
             String installerPackageName, int[] allUsers, int[] installedForUsers,
             PackageInstalledInfo res, UserHandle user, int installReason) {
         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "updateSettings");
 
-        final String pkgName = pkg.packageName;
+        final String pkgName = pkg.getPackageName();
 
-        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(pkg.packageName, pkg);
+            mPermissionManager.updatePermissions(pkg.getPackageName(), pkg);
             // For system-bundled packages, we assume that installing an upgraded version
             // of the package implies that the user actually wants to run that new code,
             // so we enable the package.
@@ -15196,7 +14964,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);
@@ -15254,7 +15022,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;
@@ -15267,7 +15035,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;
@@ -15282,7 +15050,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(),
@@ -15350,15 +15118,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;
         }
     }
 
@@ -15371,8 +15141,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 =
@@ -15382,7 +15153,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 =
@@ -15415,7 +15186,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,
@@ -15427,7 +15198,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 =
@@ -15440,35 +15211,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
@@ -15476,10 +15249,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;
@@ -15489,7 +15262,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
@@ -15504,7 +15277,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
@@ -15524,18 +15297,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) {
@@ -15569,8 +15343,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());
@@ -15588,7 +15363,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;
@@ -15599,12 +15374,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
@@ -15613,9 +15388,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 =
@@ -15633,16 +15408,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);
@@ -15680,68 +15456,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);
@@ -15757,62 +15503,40 @@
                             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;
-                                    }
-                                }
-                            }
                         }
                     }
                 }
             }
 
-            commitReconciledScanResultLocked(reconciledPkg);
+            AndroidPackage pkg = commitReconciledScanResultLocked(reconciledPkg);
             updateSettingsLI(pkg, reconciledPkg.installArgs.installerPackageName, request.mAllUsers,
                     res, reconciledPkg.installArgs.user, reconciledPkg.installArgs.installReason);
 
@@ -15821,17 +15545,6 @@
                 res.newUsers = ps.queryInstalledUsers(mUserManager.getUserIds(), true);
                 ps.setUpdateAvailable(false /*updateAvailable*/);
             }
-            final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
-            for (int i = 0; i < childCount; i++) {
-                PackageParser.Package childPkg = pkg.childPackages.get(i);
-                PackageInstalledInfo childRes = res.addedChildPackages.get(
-                        childPkg.packageName);
-                PackageSetting childPs = mSettings.getPackageLPr(childPkg.packageName);
-                if (childPs != null) {
-                    childRes.newUsers = childPs.queryInstalledUsers(
-                            mUserManager.getUserIds(), true);
-                }
-            }
             if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
                 updateSequenceNumberLP(ps, res.newUsers);
                 updateInstantAppInstallerLocked(packageName);
@@ -15891,33 +15604,31 @@
                 request.installResult.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
                 request.installResult.installerPackageName = request.args.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) {
@@ -15960,7 +15671,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);
                     }
                 }
@@ -15990,16 +15702,16 @@
         for (ReconciledPackage reconciledPkg : commitRequest.reconciledPackages.values()) {
             final boolean instantApp = ((reconciledPkg.scanResult.request.scanFlags
                             & PackageManagerService.SCAN_AS_INSTANT_APP) != 0);
-            final PackageParser.Package pkg = reconciledPkg.pkgSetting.pkg;
-            final String packageName = pkg.packageName;
+            final AndroidPackage pkg = reconciledPkg.pkgSetting.pkg;
+            final String packageName = pkg.getPackageName();
             prepareAppDataAfterInstallLIF(pkg);
             if (reconciledPkg.prepareResult.clearCodeCache) {
                 clearAppDataLIF(pkg, UserHandle.USER_ALL, FLAG_STORAGE_DE | FLAG_STORAGE_CE
                         | 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.
@@ -16013,7 +15725,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).
@@ -16032,7 +15744,7 @@
             final boolean performDexopt =
                     (!instantApp || Global.getInt(mContext.getContentResolver(),
                     Global.INSTANT_APP_DEXOPT_ENABLED, 0) != 0)
-                    && ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) == 0);
+                    && ((pkg.getFlags() & ApplicationInfo.FLAG_DEBUGGABLE) == 0);
 
             if (performDexopt) {
                 // Compile the layout resources.
@@ -16080,8 +15792,8 @@
         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;
         /* The original package name if it was changed during an update, otherwise {@code null}. */
@@ -16090,14 +15802,13 @@
         public final PackageFreezer freezer;
         public final PackageSetting originalPs;
         public final PackageSetting disabledPs;
-        public final PackageSetting[] childPackageSettings;
 
         private PrepareResult(int installReason, String volumeUuid,
                 String installerPackageName, UserHandle user, boolean replace, int scanFlags,
-                int parseFlags, PackageParser.Package existingPackage,
-                PackageParser.Package packageToScan, boolean clearCodeCache, boolean system,
+                int parseFlags, AndroidPackage existingPackage,
+                ParsedPackage packageToScan, boolean clearCodeCache, boolean system,
                 String renamedPackage, PackageFreezer freezer, PackageSetting originalPs,
-                PackageSetting disabledPs, PackageSetting[] childPackageSettings) {
+                PackageSetting disabledPs) {
             this.installReason = installReason;
             this.volumeUuid = volumeUuid;
             this.installerPackageName = installerPackageName;
@@ -16113,7 +15824,6 @@
             this.freezer = freezer;
             this.originalPs = originalPs;
             this.disabledPs = disabledPs;
-            this.childPackageSettings = childPackageSettings;
         }
     }
 
@@ -16194,10 +15904,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 {
@@ -16206,23 +15916,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) {
@@ -16232,42 +15942,16 @@
             }
         }
 
-        // If we are installing a clustered package add results for the children
-        if (pkg.childPackages != null) {
-            synchronized (mLock) {
-                final int childCount = pkg.childPackages.size();
-                for (int i = 0; i < childCount; i++) {
-                    PackageParser.Package childPkg = pkg.childPackages.get(i);
-                    PackageInstalledInfo childRes = new PackageInstalledInfo();
-                    childRes.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
-                    childRes.pkg = childPkg;
-                    childRes.name = childPkg.packageName;
-                    PackageSetting childPs = mSettings.getPackageLPr(childPkg.packageName);
-                    if (childPs != null) {
-                        childRes.origUsers = childPs.queryInstalledUsers(
-                                mUserManager.getUserIds(), true);
-                    }
-                    if ((mPackages.containsKey(childPkg.packageName))) {
-                        childRes.removedInfo = new PackageRemovedInfo(this);
-                        childRes.removedInfo.removedPackage = childPkg.packageName;
-                        childRes.removedInfo.installerPackageName = childPs.installerPackageName;
-                    }
-                    if (res.addedChildPackages == null) {
-                        res.addedChildPackages = new ArrayMap<>();
-                    }
-                    res.addedChildPackages.put(childPkg.packageName, childRes);
-                }
-            }
-        }
-
         // 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");
             }
@@ -16276,17 +15960,17 @@
         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 {
-                PackageParser.collectCertificates(pkg, false /* skipVerify */);
+                ApkParseUtils.collectCertificates(parsedPackage, false /* skipVerify */);
             }
         } catch (PackageParserException e) {
             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");
@@ -16300,15 +15984,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="
@@ -16321,43 +16005,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.");
-                    }
                 }
             }
 
@@ -16370,8 +16038,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());
                     }
@@ -16382,23 +16050,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) {
@@ -16406,27 +16074,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
@@ -16438,26 +16104,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;
@@ -16469,30 +16136,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();
                             }
                         }
                     }
@@ -16526,8 +16194,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 {
@@ -16535,14 +16203,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,
@@ -16550,19 +16218,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);
@@ -16572,7 +16240,7 @@
                 freezePackageForInstall(pkgName, installFlags, "installPackageLI");
         boolean shouldCloseFreezerBeforeReturn = true;
         try {
-            final PackageParser.Package existingPackage;
+            final AndroidPackage existingPackage;
             String renamedPackage = null;
             boolean sysPkg = false;
             String targetVolumeUuid = volumeUuid;
@@ -16583,14 +16251,15 @@
             final PackageSetting[] childPackages;
             if (replace) {
                 targetVolumeUuid = null;
-                if (pkg.applicationInfo.isStaticSharedLibrary()) {
+                if (parsedPackage.isStaticSharedLibrary()) {
                     // Static libs have a synthetic package name containing the version
                     // 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");
@@ -16599,8 +16268,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;
 
@@ -16608,8 +16277,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);
@@ -16618,17 +16288,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);
@@ -16636,13 +16307,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));
                                 }
                             }
@@ -16651,21 +16322,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
@@ -16698,10 +16373,10 @@
 
                 // Update what is removed
                 res.removedInfo = new PackageRemovedInfo(this);
-                res.removedInfo.uid = oldPackage.applicationInfo.uid;
-                res.removedInfo.removedPackage = oldPackage.packageName;
+                res.removedInfo.uid = oldPackage.getUid();
+                res.removedInfo.removedPackage = oldPackage.getPackageName();
                 res.removedInfo.installerPackageName = ps.installerPackageName;
-                res.removedInfo.isStaticSharedLib = pkg.staticSharedLibName != null;
+                res.removedInfo.isStaticSharedLib = parsedPackage.getStaticSharedLibName() != null;
                 res.removedInfo.isUpdate = true;
                 res.removedInfo.origUsers = installedUsers;
                 res.removedInfo.installReasons = new SparseArray<>(installedUsers.length);
@@ -16710,52 +16385,6 @@
                     res.removedInfo.installReasons.put(userId, ps.getInstallReason(userId));
                 }
 
-                childPackages = mSettings.getChildSettingsLPr(ps);
-                if (childPackages != null) {
-                    for (PackageSetting childPs : childPackages) {
-                        boolean childPackageUpdated = false;
-                        PackageParser.Package childPkg = (childPs == null) ? null : childPs.pkg;
-                        if (res.addedChildPackages != null) {
-                            PackageInstalledInfo childRes = res.addedChildPackages.get(
-                                    childPkg.packageName);
-                            if (childRes != null) {
-                                childRes.removedInfo.uid = childPkg.applicationInfo.uid;
-                                childRes.removedInfo.removedPackage = childPkg.packageName;
-                                if (childPs != null) {
-                                    childRes.removedInfo.installerPackageName =
-                                            childPs.installerPackageName;
-                                }
-                                childRes.removedInfo.isUpdate = true;
-                                childRes.removedInfo.installReasons =
-                                        res.removedInfo.installReasons;
-                                childPackageUpdated = true;
-                            }
-                        }
-                        if (!childPackageUpdated) {
-                            PackageRemovedInfo childRemovedRes = new PackageRemovedInfo(this);
-                            childRemovedRes.removedPackage = childPkg.packageName;
-                            if (childPs != null) {
-                                childRemovedRes.installerPackageName = childPs.installerPackageName;
-                            }
-                            childRemovedRes.isUpdate = false;
-                            childRemovedRes.dataRemoved = true;
-                            synchronized (mLock) {
-                                if (childPs != null) {
-                                    childRemovedRes.origUsers = childPs.queryInstalledUsers(
-                                            allUsers,
-                                            true);
-                                }
-                            }
-                            if (res.removedInfo.removedChildPackages == null) {
-                                res.removedInfo.removedChildPackages = new ArrayMap<>();
-                            }
-                            res.removedInfo.removedChildPackages.put(childPkg.packageName,
-                                    childRemovedRes);
-                        }
-                    }
-                }
-
-
                 sysPkg = (isSystemApp(oldPackage));
                 if (sysPkg) {
                     // Set the system/privileged/oem/vendor/product flags as needed
@@ -16774,41 +16403,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) {
@@ -16835,9 +16453,9 @@
             shouldCloseFreezerBeforeReturn = false;
 
             return new PrepareResult(args.installReason, targetVolumeUuid, installerPackageName,
-                    args.user, replace, targetScanFlags, targetParseFlags, existingPackage, pkg,
-                    replace /* clearCodeCache */, sysPkg, renamedPackage, freezer,
-                    ps, disabledPs, childPackages);
+                    args.user, replace, targetScanFlags, targetParseFlags, existingPackage,
+                    parsedPackage, replace /* clearCodeCache */, sysPkg, renamedPackage, freezer,
+                    ps, disabledPs);
         } finally {
             if (shouldCloseFreezerBeforeReturn) {
                 freezer.close();
@@ -16852,7 +16470,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();
@@ -16864,11 +16482,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);
                         }
                     }
@@ -16877,16 +16495,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);
@@ -16940,8 +16559,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!");
@@ -16954,29 +16572,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;
@@ -16987,7 +16605,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
@@ -17006,8 +16623,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,
@@ -17021,8 +16638,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());
@@ -17048,9 +16665,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);
@@ -17070,45 +16686,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) {
@@ -17119,12 +16735,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();
@@ -17132,6 +16748,7 @@
     }
 
     private void deleteTempPackageFiles() {
+        // TODO: Is this used?
         final FilenameFilter filter =
                 (dir, name) -> name.startsWith("vmdl") && name.endsWith(".tmp");
     }
@@ -17265,11 +16882,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")
@@ -17476,7 +17093,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
@@ -17508,9 +17125,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) {
@@ -17519,7 +17136,7 @@
                         List<VersionedPackage> libClientPackages = getPackagesUsingSharedLibraryLPr(
                                 libraryInfo, 0, 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);
@@ -17574,13 +17191,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");
                     }
@@ -17589,7 +17206,7 @@
                         || origEnabledState == COMPONENT_ENABLED_STATE_ENABLED) {
                     if (DEBUG_COMPRESSION) {
                         Slog.i(TAG, "Enabling system stub after removal; pkg: "
-                                + stubPkg.packageName);
+                                + stubPkg.getPackageName());
                     }
                     enableCompressedPackage(stubPkg);
                 }
@@ -17617,7 +17234,6 @@
         boolean isStaticSharedLib;
         // Clean up resources deleted packages.
         InstallArgs args = null;
-        ArrayMap<String, PackageRemovedInfo> removedChildPackages;
         ArrayMap<String, PackageInstalledInfo> appearedChildPackages;
 
         PackageRemovedInfo(PackageSender packageSender) {
@@ -17626,24 +17242,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();
-                    }
-                }
             }
         }
 
@@ -17755,12 +17358,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.installerPackageName;
             outInfo.isStaticSharedLib = deletedPkg != null
-                    && deletedPkg.staticSharedLibName != null;
+                    && deletedPkg.getStaticSharedLibName() != null;
             outInfo.populateUsers(deletedPs == null ? null
                     : deletedPs.queryInstalledUsers(mUserManager.getUserIds(), true), deletedPs);
         }
@@ -17768,14 +17371,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);
@@ -17887,13 +17490,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");
 
@@ -17910,21 +17513,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) {
@@ -17936,7 +17524,7 @@
         }
 
         deleteInstalledPackageLIF(deletedPs, true, flags, allUserHandles,
-                outInfo, writeSettings, disabledPs.pkg);
+                outInfo, writeSettings);
 
         // writer
         synchronized (mLock) {
@@ -17957,16 +17545,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");
@@ -17978,7 +17566,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 {
@@ -17999,7 +17587,7 @@
         }
 
         final File codePath = new File(codePathString);
-        final PackageParser.Package pkg =
+        final AndroidPackage pkg =
                 scanPackageTracedLI(codePath, parseFlags, scanFlags, 0 /*currentTime*/, null);
 
         try {
@@ -18013,7 +17601,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
@@ -18021,7 +17609,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);
@@ -18059,58 +17647,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);
         }
     }
 
@@ -18123,10 +17675,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);
@@ -18190,40 +17742,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);
     }
 
@@ -18233,13 +17767,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) {
@@ -18270,30 +17803,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);
@@ -18343,26 +17859,6 @@
             }
         }
 
-        // If we are deleting a composite package for all users, keep track
-        // of result for each child.
-        if (ps.childPackageNames != null && outInfo != null) {
-            synchronized (mLock) {
-                final int childCount = ps.childPackageNames.size();
-                outInfo.removedChildPackages = new ArrayMap<>(childCount);
-                for (int i = 0; i < childCount; i++) {
-                    String childPackageName = ps.childPackageNames.get(i);
-                    PackageRemovedInfo childInfo = new PackageRemovedInfo(this);
-                    childInfo.removedPackage = childPackageName;
-                    childInfo.installerPackageName = ps.installerPackageName;
-                    outInfo.removedChildPackages.put(childPackageName, childInfo);
-                    PackageSetting childPs = mSettings.getPackageLPr(childPackageName);
-                    if (childPs != null) {
-                        childInfo.origUsers = childPs.queryInstalledUsers(allUserHandles, true);
-                    }
-                }
-            }
-        }
-
         // TODO(b/109941548): break reasons for ret = false out into mayDelete method
         if (systemApp) {
             if (DEBUG_REMOVE) Slog.d(TAG, "Removing system package: " + ps.name);
@@ -18372,53 +17868,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);
-                        }
-                    }
-                }
-            }
         }
     }
 
@@ -18455,7 +17910,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);
         }
@@ -18497,7 +17952,7 @@
         if (outInfo != null) {
             outInfo.removedPackage = ps.name;
             outInfo.installerPackageName = ps.installerPackageName;
-            outInfo.isStaticSharedLib = pkg != null && pkg.staticSharedLibName != null;
+            outInfo.isStaticSharedLib = pkg != null && pkg.getStaticSharedLibName() != null;
             outInfo.removedAppId = ps.appId;
             outInfo.removedUsers = userIds;
             outInfo.broadcastUsers = userIds;
@@ -18508,7 +17963,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);
         }
@@ -18586,7 +18041,7 @@
         }
 
         // Try finding details about the requested package
-        PackageParser.Package pkg;
+        AndroidPackage pkg;
         synchronized (mLock) {
             pkg = mPackages.get(packageName);
             if (pkg == null) {
@@ -18605,7 +18060,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();
@@ -18682,14 +18137,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 =
@@ -18769,7 +18224,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;
                 }
             }
@@ -18777,7 +18232,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;
@@ -18785,9 +18240,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;
     }
@@ -18956,7 +18411,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)
@@ -19030,8 +18485,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 +19393,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 +19415,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);
@@ -20903,7 +20358,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)) {
@@ -21046,9 +20501,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 {
@@ -21059,11 +20514,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();
         }
     }
@@ -21075,9 +20530,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 {
@@ -21088,11 +20543,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 {
@@ -21163,14 +20618,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);
@@ -21213,7 +20668,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;
@@ -21226,10 +20681,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());
@@ -21301,14 +20756,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);
 
@@ -21316,7 +20771,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);
                     }
@@ -21531,7 +20986,7 @@
                 continue;
             }
             // Skip non-core apps if requested
-            if (onlyCoreApps && !ps.pkg.coreApp) {
+            if (onlyCoreApps && !ps.pkg.isCoreApp()) {
                 result.add(packageName);
                 continue;
             }
@@ -21558,10 +21013,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);
         }
 
@@ -21591,19 +21046,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);
 
@@ -21614,43 +21065,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!");
@@ -21692,29 +21137,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);
@@ -21730,17 +21170,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 {
@@ -21791,7 +21231,6 @@
      */
     private class PackageFreezer implements AutoCloseable {
         private final String mPackageName;
-        private final PackageFreezer[] mChildren;
 
         private final boolean mWeFroze;
 
@@ -21806,7 +21245,6 @@
          */
         public PackageFreezer() {
             mPackageName = null;
-            mChildren = null;
             mWeFroze = false;
             mCloseGuard.open("close");
         }
@@ -21820,18 +21258,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");
         }
@@ -21854,12 +21280,6 @@
                     if (mWeFroze) {
                         mFrozenPackages.remove(mPackageName);
                     }
-
-                    if (mChildren != null) {
-                        for (PackageFreezer freezer : mChildren) {
-                            freezer.close();
-                        }
-                    }
                 }
             }
         }
@@ -21914,14 +21334,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");
             }
@@ -21936,7 +21356,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,
@@ -21947,7 +21367,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");
             }
@@ -21958,13 +21378,13 @@
             }
 
             isCurrentLocationExternal = isExternal(pkg);
-            codeFile = new File(pkg.codePath);
+            codeFile = new File(pkg.getCodePath());
             installerPackageName = ps.installerPackageName;
             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);
         }
@@ -22125,7 +21545,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);
         }
@@ -22133,8 +21553,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)) {
@@ -22248,7 +21668,7 @@
             if (ps.pkg == null) {
                 continue;
             }
-            final String packageName = ps.pkg.packageName;
+            final String packageName = ps.pkg.getPackageName();
             // Skip over if system app
             if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0) {
                 continue;
@@ -22377,13 +21797,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);
@@ -22402,19 +21822,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.");
             }
@@ -22432,11 +21852,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);
             }
@@ -22459,10 +21879,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);
             }
@@ -22494,29 +21914,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]);
                         }
                     }
                 }
@@ -22706,13 +22126,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);
         }
 
@@ -22748,11 +22168,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();
             }
         }
 
@@ -22783,28 +22203,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);
@@ -22813,10 +22230,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]);
@@ -22825,6 +22242,12 @@
             }
         }
 
+        @Nullable
+        @Override
+        public PackageSetting getPackageSetting(String packageName) {
+            return PackageManagerService.this.getPackageSetting(packageName);
+        }
+
         @Override
         public PackageList getPackageList(PackageListObserver observer) {
             synchronized (mLock) {
@@ -22849,17 +22272,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();
         }
 
         @Override
@@ -22930,7 +22355,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;
                 }
@@ -23086,9 +22511,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);
             }
         }
 
@@ -23105,10 +22531,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;
@@ -23130,21 +22556,21 @@
         public void grantImplicitAccess(int userId, Intent intent,
                 int callingUid, int targetAppId) {
             synchronized (mLock) {
-                final PackageParser.Package callingPackage = getPackage(callingUid);
-                final PackageParser.Package targetPackage =
+                final AndroidPackage callingPackage = getPackage(callingUid);
+                final AndroidPackage targetPackage =
                         getPackage(UserHandle.getUid(userId, targetAppId));
                 if (callingPackage == null || targetPackage == null) {
                     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);
                 } else {
-                    mAppsFilter.grantImplicitAccess(
-                            callingPackage.packageName, targetPackage.packageName, userId);
+                    mAppsFilter.grantImplicitAccess(callingPackage.getPackageName(),
+                            targetPackage.getPackageName(), userId);
                 }
             }
         }
@@ -23176,9 +22602,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;
@@ -23186,9 +22612,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);
@@ -23199,9 +22625,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);
                         }
@@ -23215,9 +22642,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());
                     }
                 }
             }
@@ -23238,12 +22665,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());
                     }
                 }
 
@@ -23361,12 +22788,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);
         }
@@ -23415,7 +22842,7 @@
          */
         @Override
         public boolean compileLayouts(String packageName) {
-            PackageParser.Package pkg;
+            AndroidPackage pkg;
             synchronized (mLock) {
                 pkg = mPackages.get(packageName);
                 if (pkg == null) {
@@ -23522,12 +22949,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;
                 }
@@ -23624,7 +23051,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++) {
@@ -23633,13 +23069,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;
                 }
@@ -23656,7 +23092,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());
         }
@@ -23692,8 +23128,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) {
@@ -23803,7 +23239,7 @@
 
     boolean canHaveOatDir(String packageName) {
         synchronized (mLock) {
-            PackageParser.Package p = mPackages.get(packageName);
+            AndroidPackage p = mPackages.get(packageName);
             if (p == null) {
                 return false;
             }
@@ -23811,11 +23247,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();
         }
@@ -23826,11 +23262,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);
 
@@ -23849,19 +23286,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 3f32f3d..121d709 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;
@@ -446,7 +446,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);
                 params.sessionParams.setSize(PackageHelper.calculateInstalledSize(
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 4ea8a30..44928fb 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 writeToProto(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, 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);
                 }
             }
@@ -218,4 +215,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 029673f..09c1789 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -36,7 +36,6 @@
 import com.android.internal.annotations.VisibleForTesting;
 
 import java.io.File;
-import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Set;
@@ -51,9 +50,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
@@ -137,14 +133,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;
         init(codePath, resourcePath, legacyNativeLibraryPathString, primaryCpuAbiString,
@@ -232,8 +224,6 @@
     }
 
     private void doCopy(PackageSettingBase orig) {
-        childPackageNames = (orig.childPackageNames != null)
-                ? new ArrayList<>(orig.childPackageNames) : null;
         codePath = orig.codePath;
         codePathString = orig.codePathString;
         cpuAbiOverrideString = orig.cpuAbiOverrideString;
@@ -245,7 +235,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;
@@ -657,8 +646,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 b94047e..4f47afe 100644
--- a/services/core/java/com/android/server/pm/SELinuxMMAC.java
+++ b/services/core/java/com/android/server/pm/SELinuxMMAC.java
@@ -16,9 +16,9 @@
 
 package com.android.server.pm;
 
-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;
@@ -325,7 +325,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) {
@@ -354,8 +354,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;
     }
@@ -364,7 +364,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
@@ -491,21 +491,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 4349ea7..7d6c482 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;
@@ -466,8 +469,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) {
@@ -493,14 +496,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;
@@ -517,8 +520,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) {
@@ -531,8 +533,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);
@@ -598,19 +600,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;
@@ -628,7 +626,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;
@@ -715,7 +713,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;
@@ -793,9 +791,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) {
@@ -864,15 +859,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);
     }
@@ -949,7 +944,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;
@@ -959,8 +954,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;
                 }
@@ -970,13 +965,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;
@@ -2207,20 +2202,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();
@@ -2674,17 +2655,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.
@@ -2709,13 +2688,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]);
@@ -2727,9 +2706,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);
             }
@@ -2778,12 +2757,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.
@@ -2847,15 +2820,10 @@
             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);
@@ -3148,13 +3116,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);
                 }
             }
         }
@@ -3513,7 +3481,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 {
@@ -3562,12 +3530,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 {
@@ -3612,7 +3574,6 @@
         PackageSetting packageSetting = null;
         String version = null;
         long versionCode = 0;
-        String parentPackageName;
         try {
             name = parser.getAttributeValue(null, ATTR_NAME);
             realName = parser.getAttributeValue(null, "realName");
@@ -3624,8 +3585,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");
@@ -3752,7 +3711,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="
@@ -3771,8 +3730,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;
@@ -3880,12 +3839,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());
@@ -4038,13 +3991,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) {
@@ -4055,8 +4008,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");
@@ -4166,28 +4119,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.
@@ -4210,26 +4141,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;
@@ -4238,6 +4149,15 @@
         return userState.isMatch(componentInfo, flags);
     }
 
+    boolean isEnabledAndMatchLPr(AndroidPackage pkg, ParsedComponent component, int flags,
+            int userId) {
+        final PackageSetting ps = mPackages.get(component.getPackageName());
+        if (ps == null) return false;
+
+        final PackageUserState userState = ps.readUserState(userId);
+        return userState.isMatch(pkg.isSystem(), pkg.isEnabled(), component, flags);
+    }
+
     String getInstallerPackageNameLPr(String packageName) {
         final PackageSetting pkg = mPackages.get(packageName);
         if (pkg == null) {
@@ -4455,6 +4375,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(",");
@@ -4470,15 +4391,16 @@
             pw.print(",");
             pw.print(ps.installerPackageName != null ? ps.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]);
                     }
                 }
             }
@@ -4525,7 +4447,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);
@@ -4535,140 +4457,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]);
                 }
             }
         }
@@ -4696,40 +4601,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);
@@ -4996,22 +4901,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]);
                     }
                 }
             }
@@ -5087,22 +4994,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 2ee07a2..cff1944 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 036d1e8..793ea47 100644
--- a/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
+++ b/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
@@ -23,6 +23,7 @@
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.PackageParser;
 import android.content.pm.UserInfo;
+import android.content.pm.parsing.AndroidPackage;
 import android.content.res.Resources;
 import android.os.SystemProperties;
 import android.os.UserHandle;
@@ -151,15 +152,15 @@
                     return;
                 }
                 final boolean install =
-                        (userWhitelist == null || userWhitelist.contains(pkg.packageName))
-                        && !pkg.applicationInfo.hiddenUntilInstalled;
+                        (userWhitelist == null || userWhitelist.contains(pkg.getPackageName()))
+                        && !pkg.isHiddenUntilInstalled();
                 if (isUpgrade && !isFirstBoot && !install) {
                     return; // To be careful, we don’t uninstall apps during OTAs
                 }
                 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);
                 }
             });
         }
@@ -180,7 +181,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()) {
@@ -194,8 +195,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) {
@@ -286,7 +287,7 @@
             if (shouldInstallPackage(pkg, mWhitelitsedPackagesForUserTypes,
                     whitelistedPackages, isImplicitWhitelistMode, isSystemUser)) {
                 // Although the whitelist uses manifest names, this function returns packageNames.
-                installPackages.add(pkg.packageName);
+                installPackages.add(pkg.getPackageName());
             }
         });
         return installPackages;
@@ -307,12 +308,12 @@
      * @param isSystemUser whether the user is USER_SYSTEM (which gets special treatment).
      */
     @VisibleForTesting
-    static boolean shouldInstallPackage(PackageParser.Package sysPkg,
+    static boolean shouldInstallPackage(AndroidPackage sysPkg,
             @NonNull ArrayMap<String, Integer> userTypeWhitelist,
             @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 b3f1867..661497c 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;
@@ -386,9 +386,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;
@@ -411,23 +412,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);
@@ -437,12 +439,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));
@@ -452,15 +454,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) {
@@ -471,14 +473,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.
@@ -492,7 +493,7 @@
             try {
                 synchronized (mInstallLock) {
                     return mInstaller.compileLayouts(apkPath, packageName, outDexFile,
-                            appInfo.uid);
+                            pkg.getUid());
                 }
             } finally {
                 Binder.restoreCallingIdentity(callingId);
@@ -508,15 +509,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 f56231f..5df5380 100644
--- a/services/core/java/com/android/server/pm/dex/DexManager.java
+++ b/services/core/java/com/android/server/pm/dex/DexManager.java
@@ -595,7 +595,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 6d22faa..29248b5 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() {
@@ -297,13 +288,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;
     }
@@ -316,71 +306,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) {
@@ -390,10 +398,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);
@@ -417,17 +425,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");
         }
     }
 
@@ -445,12 +453,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;
@@ -460,8 +468,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;
@@ -541,14 +549,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());
                 }
             }
         }
@@ -568,14 +580,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;
@@ -611,9 +623,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) {
@@ -625,4 +637,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 b831374..9dadf3e 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -64,10 +64,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;
@@ -420,7 +423,8 @@
         }
     }
 
-    @Nullable BasePermission getPermission(String permName) {
+    @Nullable
+    BasePermission getPermission(String permName) {
         synchronized (mLock) {
             return mSettings.getPermissionLocked(permName);
         }
@@ -454,10 +458,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);
         }
@@ -473,7 +476,7 @@
             return null;
         }
         synchronized (mLock) {
-            return PackageParser.generatePermissionGroupInfo(
+            return PackageInfoUtils.generatePermissionGroupInfo(
                     mSettings.mPermissionGroups.get(groupName), flags);
         }
     }
@@ -597,8 +600,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) {
@@ -609,7 +617,6 @@
         if (mPackageManagerInt.filterAppAccess(pkg, callingUid, userId)) {
             return 0;
         }
-        final PackageSetting ps = (PackageSetting) pkg.mExtras;
         PermissionsState permissionsState = ps.getPermissionsState();
         return permissionsState.getPermissionFlags(permName, userId);
     }
@@ -696,8 +703,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;
         }
@@ -713,7 +722,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;
@@ -726,11 +734,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());
             }
         }
     }
@@ -762,18 +770,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]) {
@@ -804,7 +810,7 @@
 
     private int checkPermissionImpl(@NonNull String permissionName, @NonNull String packageName,
             @UserIdInt int userId) {
-        final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName);
+        final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName);
         if (pkg == null) {
             return PackageManager.PERMISSION_DENIED;
         }
@@ -812,11 +818,11 @@
                 ? PackageManager.PERMISSION_GRANTED : PackageManager.PERMISSION_DENIED;
     }
 
-    private boolean checkPermissionInternal(@NonNull Package pkg, boolean isPackageExplicit,
+    private boolean checkPermissionInternal(@NonNull AndroidPackage pkg, boolean isPackageExplicit,
             @NonNull String permissionName, boolean useRequestedPermissionsForLegacyApps,
             @UserIdInt int userId) {
         final int callingUid = getCallingUid();
-        if (isPackageExplicit || pkg.mSharedUserId == null) {
+        if (isPackageExplicit || pkg.getSharedUserId() == null) {
             if (mPackageManagerInt.filterAppAccess(pkg, callingUid, userId)) {
                 return false;
             }
@@ -826,8 +832,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 false;
         }
@@ -858,9 +865,9 @@
             final String[] packageNames = mContext.getPackageManager().getPackagesForUid(uid);
             final int packageNamesSize = packageNames != null ? packageNames.length : 0;
             for (int i = 0; i < packageNamesSize; i++) {
-                final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageNames[i]);
-                if (pkg != null && pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M
-                        && pkg.requestedPermissions.contains(permissionName)) {
+                final AndroidPackage pkg = mPackageManagerInt.getPackage(packageNames[i]);
+                if (pkg != null && pkg.getTargetSdkVersion() < Build.VERSION_CODES.M
+                        && pkg.getRequestedPermissions().contains(permissionName)) {
                     hasPermission = true;
                     break;
                 }
@@ -901,7 +908,7 @@
     }
 
     private int checkUidPermissionImpl(@NonNull String permissionName, int uid) {
-        final PackageParser.Package pkg = mPackageManagerInt.getPackage(uid);
+        final AndroidPackage pkg = mPackageManagerInt.getPackage(uid);
         return checkUidPermissionInternal(uid, pkg, permissionName, true)
                 ? PackageManager.PERMISSION_GRANTED : PackageManager.PERMISSION_DENIED;
     }
@@ -913,7 +920,7 @@
      *
      * @see SystemConfig#getSystemPermissions()
      */
-    private boolean checkUidPermissionInternal(int uid, @Nullable Package pkg,
+    private boolean checkUidPermissionInternal(int uid, @Nullable AndroidPackage pkg,
             @NonNull String permissionName, boolean useRequestedPermissionsForLegacyApps) {
         if (pkg != null) {
             final int userId = UserHandle.getUserId(uid);
@@ -948,7 +955,7 @@
     }
 
     private boolean isUidPermissionGranted(int uid, @NonNull String permissionName) {
-        final PackageParser.Package pkg = mPackageManagerInt.getPackage(uid);
+        final AndroidPackage pkg = mPackageManagerInt.getPackage(uid);
         return checkUidPermissionInternal(uid, pkg, permissionName, false);
     }
 
@@ -989,7 +996,7 @@
                     "getWhitelistedRestrictedPermissions for user " + userId);
         }
 
-        final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName);
+        final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName);
         if (pkg == null) {
             return null;
         }
@@ -1022,7 +1029,7 @@
         final long identity = Binder.clearCallingIdentity();
         try {
             final PermissionsState permissionsState =
-                    PackageManagerServiceUtils.getPermissionsState(pkg);
+                    PackageManagerServiceUtils.getPermissionsState(mPackageManagerInt, pkg);
             if (permissionsState == null) {
                 return null;
             }
@@ -1040,9 +1047,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) {
@@ -1139,7 +1146,7 @@
                     "setWhitelistedRestrictedPermissions for user " + userId);
         }
 
-        final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName);
+        final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName);
         if (pkg == null) {
             return false;
         }
@@ -1168,7 +1175,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;
@@ -1242,8 +1249,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;
         }
@@ -1258,21 +1267,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);
@@ -1295,7 +1302,7 @@
         }
 
         if (bp.isSoftRestricted() && !SoftRestrictedPermissionPolicy.forPermission(mContext,
-                pkg.applicationInfo, UserHandle.of(userId), permName).canBeGranted()) {
+                pkg, UserHandle.of(userId), permName).canBeGranted()) {
             Log.e(TAG, "Cannot grant soft restricted permission " + permName + " for package "
                     + packageName);
             return;
@@ -1318,7 +1325,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;
         }
@@ -1331,7 +1338,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;
@@ -1404,8 +1411,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;
         }
@@ -1417,18 +1426,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);
@@ -1471,7 +1479,7 @@
 
         if (callback != null) {
             callback.onPermissionRevoked(UserHandle.getUid(userId,
-                    UserHandle.getAppId(pkg.applicationInfo.uid)), userId);
+                    UserHandle.getAppId(pkg.getUid())), userId);
         }
 
         if (bp.isRuntime()) {
@@ -1496,7 +1504,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));
         }
     }
 
@@ -1507,9 +1515,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
@@ -1521,7 +1529,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);
@@ -1579,7 +1587,7 @@
 
         final AppOpsManager appOpsManager = mContext.getSystemService(AppOpsManager.class);
         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);
@@ -1594,7 +1602,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) {
@@ -1602,10 +1610,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;
                     }
@@ -2028,15 +2036,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;
         }
@@ -2057,35 +2066,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);
 
@@ -2103,7 +2112,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 +
@@ -2124,54 +2133,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);
@@ -2181,12 +2192,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);
@@ -2194,7 +2205,7 @@
                         r.append(' ');
                     }
                     r.append("DUP:");
-                    r.append(pg.info.name);
+                    r.append(pg.getName());
                 }
             }
         }
@@ -2204,15 +2215,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);
@@ -2222,14 +2233,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());
                     }
                 }
             }
@@ -2237,14 +2248,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);
                         }
@@ -2273,7 +2284,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
@@ -2286,7 +2297,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;
         }
@@ -2327,23 +2339,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;
@@ -2352,14 +2366,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
@@ -2382,7 +2396,7 @@
 
                                 if (DEBUG_PERMISSIONS) {
                                     Slog.i(TAG, permName + " is newly added for "
-                                            + pkg.packageName);
+                                            + pkg.getPackageName());
                                 }
                                 break;
                             }
@@ -2391,10 +2405,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;
                 }
@@ -2402,7 +2416,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;
                 }
@@ -2413,7 +2427,7 @@
 
                 // Keep track of app op permissions.
                 if (bp.isAppOp()) {
-                    mSettings.addAppOpPackage(perm, pkg.packageName);
+                    mSettings.addAppOpPackage(perm, pkg.getPackageName());
                 }
 
                 if (bp.isNormal()) {
@@ -2439,7 +2453,7 @@
 
                 if (DEBUG_PERMISSIONS) {
                     Slog.i(TAG, "Considering granting permission " + perm + " to package "
-                            + pkg.packageName);
+                            + pkg.getPackageName());
                 }
 
                 if (grant != GRANT_DENIED) {
@@ -2725,10 +2739,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");
                                 }
                             }
@@ -2743,9 +2757,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()) {
@@ -2753,11 +2767,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())
                                     + ")");
                         }
                     }
@@ -2787,7 +2801,7 @@
         }
 
         for (int userId : updatedUserIds) {
-            notifyRuntimePermissionStateChanged(pkg.packageName, userId);
+            notifyRuntimePermissionStateChanged(pkg.getPackageName(), userId);
         }
     }
 
@@ -2803,10 +2817,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();
@@ -2815,7 +2829,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();
 
@@ -2865,9 +2879,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;
 
@@ -2914,10 +2928,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();
         }
 
@@ -2936,10 +2950,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();
@@ -3019,17 +3033,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;
             }
         }
@@ -3043,29 +3057,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();
@@ -3073,7 +3084,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)) {
@@ -3083,22 +3094,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) {
@@ -3106,7 +3117,7 @@
                                 mPrivappPermissionsViolations = new ArraySet<>();
                             }
                             mPrivappPermissionsViolations.add(
-                                    pkg.packageName + " (" + pkg.codePath + "): " + perm);
+                                    pkg.getPackageName() + " (" + pkg.getCodePath() + "): " + perm);
                         }
                     } else {
                         return false;
@@ -3119,7 +3130,7 @@
         }
         final String systemPackageName = mPackageManagerInt.getKnownPackageName(
                 PackageManagerInternal.PACKAGE_SYSTEM, UserHandle.USER_SYSTEM);
-        final PackageParser.Package systemPackage =
+        final AndroidPackage systemPackage =
                 mPackageManagerInt.getPackage(systemPackageName);
 
         // check if the package is allow to use this signature permission.  A package is allowed to
@@ -3130,24 +3141,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
@@ -3172,40 +3182,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));
@@ -3216,7 +3196,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;
                 }
             }
@@ -3224,7 +3205,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.
@@ -3234,9 +3215,9 @@
             //                  need a separate flag anymore. Hence we need to check which
             //                  permissions are needed by the permission controller
             if (!allowed && bp.isInstaller()
-                    && (pkg.packageName.equals(mPackageManagerInt.getKnownPackageName(
+                    && (pkg.getPackageName().equals(mPackageManagerInt.getKnownPackageName(
                             PackageManagerInternal.PACKAGE_INSTALLER, UserHandle.USER_SYSTEM))
-                    || pkg.packageName.equals(mPackageManagerInt.getKnownPackageName(
+                    || pkg.getPackageName().equals(mPackageManagerInt.getKnownPackageName(
                             PackageManagerInternal.PACKAGE_PERMISSION_CONTROLLER,
                             UserHandle.USER_SYSTEM)))) {
                 // If this permission is to be granted to the system installer and
@@ -3244,7 +3225,7 @@
                 allowed = true;
             }
             if (!allowed && bp.isVerifier()
-                    && pkg.packageName.equals(mPackageManagerInt.getKnownPackageName(
+                    && pkg.getPackageName().equals(mPackageManagerInt.getKnownPackageName(
                             PackageManagerInternal.PACKAGE_VERIFIER, UserHandle.USER_SYSTEM))) {
                 // If this permission is to be granted to the system verifier and
                 // this app is a verifier, then it gets the permission.
@@ -3261,41 +3242,41 @@
                 allowed = origPermissions.hasInstallPermission(perm);
             }
             if (!allowed && bp.isSetup()
-                    && pkg.packageName.equals(mPackageManagerInt.getKnownPackageName(
+                    && pkg.getPackageName().equals(mPackageManagerInt.getKnownPackageName(
                             PackageManagerInternal.PACKAGE_SETUP_WIZARD, UserHandle.USER_SYSTEM))) {
                 // If this permission is to be granted to the system setup wizard and
                 // this app is a setup wizard, then it gets the permission.
                 allowed = true;
             }
             if (!allowed && bp.isSystemTextClassifier()
-                    && pkg.packageName.equals(mPackageManagerInt.getKnownPackageName(
+                    && pkg.getPackageName().equals(mPackageManagerInt.getKnownPackageName(
                             PackageManagerInternal.PACKAGE_SYSTEM_TEXT_CLASSIFIER,
                             UserHandle.USER_SYSTEM))) {
                 // Special permissions for the system default text classifier.
                 allowed = true;
             }
             if (!allowed && bp.isConfigurator()
-                    && pkg.packageName.equals(mPackageManagerInt.getKnownPackageName(
+                    && pkg.getPackageName().equals(mPackageManagerInt.getKnownPackageName(
                     PackageManagerInternal.PACKAGE_CONFIGURATOR,
                     UserHandle.USER_SYSTEM))) {
                 // Special permissions for the device configurator.
                 allowed = true;
             }
             if (!allowed && bp.isWellbeing()
-                    && pkg.packageName.equals(mPackageManagerInt.getKnownPackageName(
+                    && pkg.getPackageName().equals(mPackageManagerInt.getKnownPackageName(
                     PackageManagerInternal.PACKAGE_WELLBEING, UserHandle.USER_SYSTEM))) {
                 // Special permission granted only to the OEM specified wellbeing app
                 allowed = true;
             }
             if (!allowed && bp.isDocumenter()
-                    && pkg.packageName.equals(mPackageManagerInt.getKnownPackageName(
+                    && pkg.getPackageName().equals(mPackageManagerInt.getKnownPackageName(
                             PackageManagerInternal.PACKAGE_DOCUMENTER, UserHandle.USER_SYSTEM))) {
                 // If this permission is to be granted to the documenter and
                 // this app is the documenter, then it gets the permission.
                 allowed = true;
             }
             if (!allowed && bp.isIncidentReportApprover()
-                    && pkg.packageName.equals(mPackageManagerInt.getKnownPackageName(
+                    && pkg.getPackageName().equals(mPackageManagerInt.getKnownPackageName(
                             PackageManagerInternal.PACKAGE_INCIDENT_REPORT_APPROVER,
                             UserHandle.USER_SYSTEM))) {
                 // If this permission is to be granted to the incident report approver and
@@ -3303,7 +3284,7 @@
                 allowed = true;
             }
             if (!allowed && bp.isAppPredictor()
-                    && pkg.packageName.equals(mPackageManagerInt.getKnownPackageName(
+                    && pkg.getPackageName().equals(mPackageManagerInt.getKnownPackageName(
                         PackageManagerInternal.PACKAGE_APP_PREDICTOR, UserHandle.USER_SYSTEM))) {
                 // Special permissions for the system app predictor.
                 allowed = true;
@@ -3326,26 +3307,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;
             }
@@ -3353,41 +3335,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,
@@ -3395,9 +3343,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;
         }
@@ -3407,12 +3356,12 @@
         final int immutableFlags = PackageManager.FLAG_PERMISSION_SYSTEM_FIXED
                 | PackageManager.FLAG_PERMISSION_POLICY_FIXED;
 
-        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);
@@ -3426,14 +3375,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 when we
                     // are asked to install the app with all permissions granted.
                     if ((flags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) != 0) {
-                        updatePermissionFlagsInternal(permission, pkg.packageName,
+                        updatePermissionFlagsInternal(permission, pkg.getPackageName(),
                                 PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED, 0, callingUid,
                                 userId, false, callback);
                     }
@@ -3442,11 +3391,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;
         }
@@ -3454,9 +3403,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);
 
@@ -3532,19 +3481,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) {
@@ -3553,9 +3502,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;
                     }
                 }
@@ -3568,17 +3517,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);
@@ -3640,18 +3589,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);
-            }
-        }
     }
 
     /**
@@ -3687,10 +3630,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) {
@@ -3751,7 +3693,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) {
@@ -3784,7 +3726,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;
                 }
@@ -3823,7 +3765,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;
 
@@ -3846,8 +3788,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);
@@ -3892,11 +3834,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);
                         }
@@ -3929,7 +3873,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;
@@ -3955,11 +3899,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);
                         }
@@ -4082,24 +4028,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;
             }
         }
@@ -4138,37 +4088,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) {
@@ -4183,13 +4135,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);
         }
@@ -4199,13 +4145,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) {
@@ -4251,9 +4197,9 @@
                 for (int i = 0; i < numTotalPermissions; i++) {
                     BasePermission bp = mSettings.mPermissions.valueAt(i);
 
-                    if (bp.perm != null && bp.perm.info != null
-                            && bp.protectionLevel == protectionLevel) {
-                        matchingPermissions.add(bp.perm.info);
+                    if (bp.perm != null && bp.protectionLevel == protectionLevel) {
+                        matchingPermissions.add(
+                                PackageInfoUtils.generatePermissionInfo(bp.perm, 0));
                     }
                 }
             }
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 8f22f92..752c2dc 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;
@@ -173,16 +173,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. */
@@ -204,7 +202,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.
@@ -224,7 +222,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);
 
@@ -232,7 +230,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);
 
     /**
@@ -245,8 +243,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);
 
     /**
@@ -255,9 +253,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/pm/permission/PermissionsState.java b/services/core/java/com/android/server/pm/permission/PermissionsState.java
index 505a0e2..a78f5c4 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionsState.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionsState.java
@@ -23,6 +23,7 @@
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.ArrayUtils;
 
 import java.util.ArrayList;
@@ -30,7 +31,6 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.Set;
-import com.android.internal.annotations.GuardedBy;
 
 /**
  * This class encapsulates the permissions for a package or a shared user.
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java
index 1bf319d..a98de89 100644
--- a/services/core/java/com/android/server/policy/PermissionPolicyService.java
+++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java
@@ -38,8 +38,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;
@@ -159,7 +159,8 @@
                     appOpsService.startWatchingMode(getSwitchOp(perm.name), null, appOpsListener);
 
                     SoftRestrictedPermissionPolicy policy =
-                            SoftRestrictedPermissionPolicy.forPermission(null, null, null,
+                            SoftRestrictedPermissionPolicy.forPermission(null,
+                                    (AndroidPackage) null, null,
                                     perm.name);
                     if (policy.resolveAppOp() != OP_NONE) {
                         appOpsService.startWatchingMode(policy.resolveAppOp(), null,
@@ -358,10 +359,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());
                 }
             }
         }
@@ -378,7 +379,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/policy/SoftRestrictedPermissionPolicy.java b/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java
index c1a6dbd..34c9258 100644
--- a/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java
+++ b/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java
@@ -36,6 +36,7 @@
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.parsing.AndroidPackage;
 import android.os.Build;
 import android.os.UserHandle;
 
@@ -251,6 +252,87 @@
     }
 
     /**
+     * Get the policy for a soft restricted permission.
+     *
+     * @param context A context to use
+     * @param pkg The application the permission belongs to. Can be {@code null}, but then
+     *                only {@link #resolveAppOp} will work.
+     * @param user The user the app belongs to. Can be {@code null}, but then only
+     *             {@link #resolveAppOp} will work.
+     * @param permission The name of the permission
+     *
+     * @return The policy for this permission
+     */
+    public static @NonNull SoftRestrictedPermissionPolicy forPermission(@NonNull Context context,
+            @Nullable AndroidPackage pkg, @Nullable UserHandle user,
+            @NonNull String permission) {
+        switch (permission) {
+            // Storage uses a special app op to decide the mount state and supports soft restriction
+            // where the restricted state allows the permission but only for accessing the medial
+            // collections.
+            case READ_EXTERNAL_STORAGE:
+            case WRITE_EXTERNAL_STORAGE: {
+                final int flags;
+                final boolean applyRestriction;
+                final boolean isWhiteListed;
+                final boolean hasRequestedLegacyExternalStorage;
+                final int targetSDK;
+
+                if (pkg != null) {
+                    flags = context.getPackageManager().getPermissionFlags(permission,
+                            pkg.getPackageName(), user);
+                    applyRestriction = (flags & FLAG_PERMISSION_APPLY_RESTRICTION) != 0;
+                    isWhiteListed = (flags & FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT) != 0;
+                    hasRequestedLegacyExternalStorage = pkg.hasRequestedLegacyExternalStorage();
+                    targetSDK = pkg.getTargetSdkVersion();
+                } else {
+                    flags = 0;
+                    applyRestriction = false;
+                    isWhiteListed = false;
+                    hasRequestedLegacyExternalStorage = false;
+                    targetSDK = 0;
+                }
+
+                return new SoftRestrictedPermissionPolicy() {
+                    @Override
+                    public int resolveAppOp() {
+                        return OP_LEGACY_STORAGE;
+                    }
+
+                    @Override
+                    public int getDesiredOpMode() {
+                        if (applyRestriction) {
+                            return MODE_DEFAULT;
+                        } else if (hasRequestedLegacyExternalStorage) {
+                            return MODE_ALLOWED;
+                        } else {
+                            return MODE_IGNORED;
+                        }
+                    }
+
+                    @Override
+                    public boolean shouldSetAppOpIfNotDefault() {
+                        // Do not switch from allowed -> ignored as this would mean to retroactively
+                        // turn on isolated storage. This will make the app loose all its files.
+                        return getDesiredOpMode() != MODE_IGNORED;
+                    }
+
+                    @Override
+                    public boolean canBeGranted() {
+                        if (isWhiteListed || targetSDK >= Build.VERSION_CODES.Q) {
+                            return true;
+                        } else {
+                            return false;
+                        }
+                    }
+                };
+            }
+            default:
+                return DUMMY_POLICY;
+        }
+    }
+
+    /**
      * @return An app op to be changed based on the state of the permission or
      * {@link AppOpsManager#OP_NONE} if not app-op should be set.
      */
diff --git a/services/core/java/com/android/server/role/RoleManagerService.java b/services/core/java/com/android/server/role/RoleManagerService.java
index bf8c042..0687635 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 819091c..e020945 100644
--- a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
@@ -27,10 +27,13 @@
 
 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.parsing.AndroidPackage;
+import android.content.pm.parsing.ComponentParseUtils.ParsedActivity;
+import android.content.pm.parsing.ComponentParseUtils.ParsedActivityIntentInfo;
+import android.content.pm.parsing.PackageImpl;
+import android.content.pm.parsing.ParsingPackage;
 import android.os.Build;
 import android.os.Process;
 import android.permission.IPermissionManager;
@@ -56,45 +59,55 @@
     @Mock
     AppsFilter.FeatureConfig mFeatureConfigMock;
 
-    private Map<String, PackageParser.Package> mExisting = new ArrayMap<>();
+    private Map<String, AndroidPackage> 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 PackageBuilder pkg(String packageName, String... queriesPackages) {
-        return pkg(packageName).setQueriesPackages(queriesPackages);
-    }
-
-    private static PackageBuilder pkg(String packageName, IntentFilter... filters) {
-        final PackageBuilder packageBuilder = pkg(packageName).addActivity(
-                pkg -> new PackageParser.ParseComponentArgs(pkg, new String[1], 0, 0, 0, 0, 0, 0,
-                        new String[]{packageName}, 0, 0, 0), new ActivityInfo());
-        for (IntentFilter filter : filters) {
-            packageBuilder.addActivityIntentInfo(0 /* index */, activity -> {
-                final PackageParser.ActivityIntentInfo info =
-                        new PackageParser.ActivityIntentInfo(activity);
-                if (filter.countActions() > 0) {
-                    filter.actionsIterator().forEachRemaining(info::addAction);
-                }
-                if (filter.countCategories() > 0) {
-                    filter.actionsIterator().forEachRemaining(info::addAction);
-                }
-                if (filter.countDataAuthorities() > 0) {
-                    filter.authoritiesIterator().forEachRemaining(info::addDataAuthority);
-                }
-                if (filter.countDataSchemes() > 0) {
-                    filter.schemesIterator().forEachRemaining(info::addDataScheme);
-                }
-                return info;
-            });
+    private static ParsingPackage pkg(String packageName, Intent... queries) {
+        ParsingPackage pkg = pkg(packageName);
+        if (queries != null) {
+            for (Intent intent : queries) {
+                pkg.addQueriesIntent(intent);
+            }
         }
-        return packageBuilder;
+        return pkg;
+    }
+
+    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 ParsingPackage pkg(String packageName, IntentFilter... filters) {
+        ParsedActivity activity = new ParsedActivity();
+        activity.setPackageName(packageName);
+        for (IntentFilter filter : filters) {
+            final ParsedActivityIntentInfo info = new ParsedActivityIntentInfo(packageName, null);
+            if (filter.countActions() > 0) {
+                filter.actionsIterator().forEachRemaining(info::addAction);
+            }
+            if (filter.countCategories() > 0) {
+                filter.actionsIterator().forEachRemaining(info::addAction);
+            }
+            if (filter.countDataAuthorities() > 0) {
+                filter.authoritiesIterator().forEachRemaining(info::addDataAuthority);
+            }
+            if (filter.countDataSchemes() > 0) {
+                filter.schemesIterator().forEachRemaining(info::addDataScheme);
+            }
+            activity.addIntent(info);
+        }
+
+        return pkg(packageName)
+                .addActivity(activity);
     }
 
     @Before
@@ -106,7 +119,7 @@
                 .checkPermission(anyString(), anyString(), anyInt()))
                 .thenReturn(PackageManager.PERMISSION_DENIED);
         when(mFeatureConfigMock.isGloballyEnabled()).thenReturn(true);
-        when(mFeatureConfigMock.packageIsEnabled(any(PackageParser.Package.class)))
+        when(mFeatureConfigMock.packageIsEnabled(any(AndroidPackage.class)))
                 .thenReturn(true);
     }
 
@@ -152,7 +165,7 @@
 
         PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package")).build();
         PackageSetting calling = simulateAddPackage(appsFilter, pkg("com.some.other.package",
-                new Intent("TEST_ACTION")).setApplicationInfoTargetSdkVersion(
+                new Intent("TEST_ACTION")).setTargetSdkVersion(
                 Build.VERSION_CODES.P)).build();
 
         assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
@@ -245,7 +258,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, mPermissionManagerMock,
@@ -301,13 +314,15 @@
     }
 
     private PackageSettingBuilder simulateAddPackage(AppsFilter filter,
-            PackageBuilder newPkgBuilder) {
-        PackageParser.Package newPkg = newPkgBuilder.build();
+            ParsingPackage newPkgBuilder) {
+        AndroidPackage newPkg = newPkgBuilder
+                .hideAsParsed()
+                .hideAsFinal();
         filter.addPackage(newPkg, mExisting);
-        mExisting.put(newPkg.packageName, newPkg);
+        mExisting.put(newPkg.getPackageName(), newPkg);
         return new PackageSettingBuilder()
                 .setPackage(newPkg)
-                .setName(newPkg.packageName)
+                .setName(newPkg.getPackageName())
                 .setCodePath("/")
                 .setResourcePath("/")
                 .setPVersionCode(1L);
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 3fe9b52..6836d3b 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -346,10 +346,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 =
@@ -359,10 +355,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,
@@ -375,8 +367,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*/);
@@ -386,10 +376,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*/,
@@ -402,8 +388,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*/);
@@ -419,8 +403,6 @@
                 UPDATED_VERSION_CODE,
                 0 /*pkgFlags*/,
                 0 /*pkgPrivateFlags*/,
-                null /*parentPkgName*/,
-                null /*childPkgNames*/,
                 0,
                 null /*usesStaticLibraries*/,
                 null /*usesStaticLibrariesVersions*/);
@@ -448,7 +430,6 @@
                 "armeabi" /*secondaryCpuAbi*/,
                 0 /*pkgFlags*/,
                 0 /*pkgPrivateFlags*/,
-                null /*childPkgNames*/,
                 UserManagerService.getInstance(),
                 null /*usesStaticLibraries*/,
                 null /*usesStaticLibrariesVersions*/);
@@ -482,7 +463,6 @@
                 "armeabi" /*secondaryCpuAbi*/,
                 ApplicationInfo.FLAG_SYSTEM /*pkgFlags*/,
                 ApplicationInfo.PRIVATE_FLAG_PRIVILEGED /*pkgPrivateFlags*/,
-                null /*childPkgNames*/,
                 UserManagerService.getInstance(),
                 null /*usesStaticLibraries*/,
                 null /*usesStaticLibrariesVersions*/);
@@ -522,7 +502,6 @@
                     "armeabi" /*secondaryCpuAbi*/,
                     0 /*pkgFlags*/,
                     0 /*pkgPrivateFlags*/,
-                    null /*childPkgNames*/,
                     UserManagerService.getInstance(),
                     null /*usesStaticLibraries*/,
                     null /*usesStaticLibrariesVersions*/);
@@ -555,8 +534,6 @@
                 false /*allowInstall*/,
                 false /*instantApp*/,
                 false /*virtualPreload*/,
-                null /*parentPkgName*/,
-                null /*childPkgNames*/,
                 UserManagerService.getInstance(),
                 null /*usesStaticLibraries*/,
                 null /*usesStaticLibrariesVersions*/);
@@ -596,8 +573,6 @@
                 true /*allowInstall*/,
                 false /*instantApp*/,
                 false /*virtualPreload*/,
-                null /*parentPkgName*/,
-                null /*childPkgNames*/,
                 UserManagerService.getInstance(),
                 null /*usesStaticLibraries*/,
                 null /*usesStaticLibrariesVersions*/);
@@ -643,8 +618,6 @@
                 false /*allowInstall*/,
                 false /*instantApp*/,
                 false /*virtualPreload*/,
-                null /*parentPkgName*/,
-                null /*childPkgNames*/,
                 UserManagerService.getInstance(),
                 null /*usesStaticLibraries*/,
                 null /*usesStaticLibrariesVersions*/);
@@ -687,8 +660,6 @@
                 false /*allowInstall*/,
                 false /*instantApp*/,
                 false /*virtualPreload*/,
-                null /*parentPkgName*/,
-                null /*childPkgNames*/,
                 UserManagerService.getInstance(),
                 null /*usesStaticLibraries*/,
                 null /*usesStaticLibrariesVersions*/);
@@ -745,9 +716,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);
@@ -773,8 +741,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));
@@ -826,8 +792,6 @@
                 INITIAL_VERSION_CODE,
                 pkgFlags,
                 0 /*privateFlags*/,
-                null /*parentPackageName*/,
-                null /*childPackageNames*/,
                 sharedUserId,
                 null /*usesStaticLibraries*/,
                 null /*usesStaticLibrariesVersions*/);
@@ -846,8 +810,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 06c6314..ca9e5b1 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,16 +34,14 @@
     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;
     private String mVolumeUuid;
     private SparseArray<PackageUserState> mUserStates = new SparseArray<>();
-    private PackageParser.Package mPkg;
+    private AndroidPackage mPkg;
 
-    public PackageSettingBuilder setPackage(PackageParser.Package pkg) {
+    public PackageSettingBuilder setPackage(AndroidPackage pkg) {
         this.mPkg = pkg;
         return this;
     }
@@ -105,16 +102,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;
@@ -148,9 +135,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.volumeUuid = this.mVolumeUuid;
         for (int i = 0; i < mUserStates.size(); i++) {
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 05905d9..1f027a3 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;
@@ -58,6 +62,7 @@
 import org.mockito.junit.MockitoJUnitRunner;
 
 import java.io.File;
+import java.util.UUID;
 
 @RunWith(MockitoJUnitRunner.class)
 @Presubmit
@@ -66,6 +71,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
@@ -87,25 +95,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();
@@ -123,7 +131,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)
@@ -138,7 +146,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();
 
@@ -149,7 +157,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);
@@ -165,7 +173,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();
@@ -197,7 +205,7 @@
                         .build();
 
         final PackageManagerService.ScanRequest scanRequest =
-                createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
+                createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME))
                         .setPkgSetting(existingPkgSetting)
                         .build();
 
@@ -209,17 +217,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);
@@ -240,15 +249,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();
@@ -290,15 +298,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
@@ -306,10 +314,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(
@@ -326,9 +334,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 =
@@ -336,7 +344,7 @@
                         .setOriginalPkgSetting(originalPkgSetting)
                         .build());
 
-        assertThat(result.request.pkg.packageName, is("original.package"));
+        assertThat(result.request.parsedPackage.getPackageName(), is("original.package"));
     }
 
     @Test
@@ -349,7 +357,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();
@@ -370,7 +378,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();
@@ -389,7 +397,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)
@@ -397,15 +405,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(),
@@ -413,15 +420,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)
@@ -476,22 +483,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);
     }
@@ -503,20 +517,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)));
@@ -524,20 +536,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"));
 
@@ -549,7 +562,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 f0b0328..ddda10e 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;
@@ -220,10 +221,10 @@
 
         final UserSystemPackageInstaller uspi = new UserSystemPackageInstaller(null, pkgFlgMap);
 
-        final PackageParser.Package pkg1 = new PackageParser.Package(packageName1);
-        final PackageParser.Package pkg2 = new PackageParser.Package(packageName2);
-        final PackageParser.Package pkg3 = new PackageParser.Package(packageName3);
-        final PackageParser.Package pkg4 = new PackageParser.Package(packageName4);
+        final AndroidPackage pkg1 = PackageImpl.forParsing(packageName1).hideAsParsed().hideAsFinal();
+        final AndroidPackage pkg2 = PackageImpl.forParsing(packageName2).hideAsParsed().hideAsFinal();
+        final AndroidPackage pkg3 = PackageImpl.forParsing(packageName3).hideAsParsed().hideAsFinal();
+        final AndroidPackage pkg4 = PackageImpl.forParsing(packageName4).hideAsParsed().hideAsFinal();
 
         // No implicit whitelist, so only install pkg1.
         boolean implicit = false;
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]);