Important migration for new ParsingPackage/ParsedPackage split

Part of the Parsing/ParsedPackage split into core/server.

This splits all the "important" changes, or those which change
significant code/logic and that requires a closer look during
review.

Bug: 135203078

Test: enumerated in first commit of change ID
		Ib4fe51d729a56bfb0ea1316e577358ba0dfceccf

Change-Id: Ie0e4394de2b3063121d850060fcd58622511c59d
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 168679e..ccb307d 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -79,14 +79,10 @@
 import android.os.Parcelable;
 import android.os.PatternMatcher;
 import android.os.RemoteException;
-import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.Trace;
 import android.os.UserHandle;
 import android.os.storage.StorageManager;
-import android.system.ErrnoException;
-import android.system.OsConstants;
-import android.system.StructStat;
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
@@ -118,7 +114,6 @@
 
 import java.io.File;
 import java.io.FileDescriptor;
-import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
@@ -316,8 +311,8 @@
 
     public int mParseError = PackageManager.INSTALL_SUCCEEDED;
 
-    public ThreadLocal<ApkParseUtils.ParseResult> mSharedResult
-            = ThreadLocal.withInitial(ApkParseUtils.ParseResult::new);
+    public ThreadLocal<ParsingPackageUtils.ParseResult> mSharedResult
+            = ThreadLocal.withInitial(ParsingPackageUtils.ParseResult::new);
 
     public static boolean sCompatibilityModeEnabled = true;
     public static boolean sUseRoundIcon = false;
@@ -1054,7 +1049,7 @@
      * and unique split names.
      * <p>
      * Note that this <em>does not</em> perform signature verification; that
-     * must be done separately in {@link ApkParseUtils#collectCertificates(AndroidPackage, boolean)}.
+     * must be done separately in {@link #collectCertificates(Package, 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
@@ -1082,201 +1077,6 @@
     }
 
     /**
-     * Updated method which returns {@link ParsedPackage}, the current representation of a
-     * package parsed from disk.
-     *
-     * @see #parsePackage(File, int, boolean)
-     */
-    @AnyThread
-    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;
-        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);
-        if (LOG_PARSE_TIMINGS) {
-            parseTime = cacheTime - parseTime;
-            cacheTime = SystemClock.uptimeMillis() - cacheTime;
-            if (parseTime + cacheTime > LOG_PARSE_TIMINGS_THRESHOLD_MS) {
-                Slog.i(TAG, "Parse times for '" + packageFile + "': parse=" + parseTime
-                        + "ms, update_cache=" + cacheTime + " ms");
-            }
-        }
-
-        return parsed;
-    }
-
-    /**
-     * 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());
-        sb.append('-');
-        sb.append(flags);
-
-        return sb.toString();
-    }
-
-    @VisibleForTesting
-    protected ParsedPackage fromCacheEntry(byte[] bytes) {
-        return fromCacheEntryStatic(bytes);
-    }
-
-    /** static version of {@link #fromCacheEntry} for unit tests. */
-    @VisibleForTesting
-    public static ParsedPackage fromCacheEntryStatic(byte[] bytes) {
-        final Parcel p = Parcel.obtain();
-        p.unmarshall(bytes, 0, bytes.length);
-        p.setDataPosition(0);
-
-        final ReadHelper helper = new ReadHelper(p);
-        helper.startAndInstall();
-
-        // TODO(b/135203078): Hide PackageImpl constructor?
-        ParsedPackage pkg = new PackageImpl(p);
-
-        p.recycle();
-
-        sCachedPackageReadCount.incrementAndGet();
-
-        return pkg;
-    }
-
-    @VisibleForTesting
-    protected byte[] toCacheEntry(ParsedPackage pkg) {
-        return toCacheEntryStatic(pkg);
-
-    }
-
-    /** static version of {@link #toCacheEntry} for unit tests. */
-    @VisibleForTesting
-    public static byte[] toCacheEntryStatic(ParsedPackage pkg) {
-        final Parcel p = Parcel.obtain();
-        final WriteHelper helper = new WriteHelper(p);
-
-        pkg.writeToParcel(p, 0 /* flags */);
-
-        helper.finishAndUninstall();
-
-        byte[] serialized = p.marshall();
-        p.recycle();
-
-        return serialized;
-    }
-
-    /**
-     * Given a {@code packageFile} and a {@code cacheFile} returns whether the
-     * cache file is up to date based on the mod-time of both files.
-     */
-    private static boolean isCacheUpToDate(File packageFile, File cacheFile) {
-        try {
-            // NOTE: We don't use the File.lastModified API because it has the very
-            // non-ideal failure mode of returning 0 with no excepions thrown.
-            // The nio2 Files API is a little better but is considerably more expensive.
-            final StructStat pkg = android.system.Os.stat(packageFile.getAbsolutePath());
-            final StructStat cache = android.system.Os.stat(cacheFile.getAbsolutePath());
-            return pkg.st_mtime < cache.st_mtime;
-        } catch (ErrnoException ee) {
-            // The most common reason why stat fails is that a given cache file doesn't
-            // exist. We ignore that here. It's easy to reason that it's safe to say the
-            // cache isn't up to date if we see any sort of exception here.
-            //
-            // (1) Exception while stating the package file : This should never happen,
-            // and if it does, we do a full package parse (which is likely to throw the
-            // same exception).
-            // (2) Exception while stating the cache file : If the file doesn't exist, the
-            // cache is obviously out of date. If the file *does* exist, we can't read it.
-            // We will attempt to delete and recreate it after parsing the package.
-            if (ee.errno != OsConstants.ENOENT) {
-                Slog.w("Error while stating package cache : ", ee);
-            }
-
-            return false;
-        }
-    }
-
-    /**
-     * Returns the cached parse result for {@code packageFile} for parse flags {@code flags},
-     * or {@code null} if no cached result exists.
-     */
-    public ParsedPackage getCachedResult(File packageFile, int flags) {
-        if (mCacheDir == null) {
-            return null;
-        }
-
-        final String cacheKey = getCacheKey(packageFile, flags);
-        final File cacheFile = new File(mCacheDir, cacheKey);
-
-        try {
-            // If the cache is not up to date, return null.
-            if (!isCacheUpToDate(packageFile, cacheFile)) {
-                return null;
-            }
-
-            final byte[] bytes = IoUtils.readFileAsByteArray(cacheFile.getAbsolutePath());
-            return fromCacheEntry(bytes);
-        } catch (Throwable e) {
-            Slog.w(TAG, "Error reading package cache: ", e);
-
-            // If something went wrong while reading the cache entry, delete the cache file
-            // so that we regenerate it the next time.
-            cacheFile.delete();
-            return null;
-        }
-    }
-
-    /**
-     * Caches the parse result for {@code packageFile} with flags {@code flags}.
-     */
-    public void cacheResult(File packageFile, int flags, ParsedPackage parsed) {
-        if (mCacheDir == null) {
-            return;
-        }
-
-        try {
-            final String cacheKey = getCacheKey(packageFile, flags);
-            final File cacheFile = new File(mCacheDir, cacheKey);
-
-            if (cacheFile.exists()) {
-                if (!cacheFile.delete()) {
-                    Slog.e(TAG, "Unable to delete cache file: " + cacheFile);
-                }
-            }
-
-            final byte[] cacheEntry = toCacheEntry(parsed);
-
-            if (cacheEntry == null) {
-                return;
-            }
-
-            try (FileOutputStream fos = new FileOutputStream(cacheFile)) {
-                fos.write(cacheEntry);
-            } catch (IOException ioe) {
-                Slog.w(TAG, "Error writing cache entry.", ioe);
-                cacheFile.delete();
-            }
-        } catch (Throwable e) {
-            Slog.w(TAG, "Error saving package cache.", e);
-        }
-    }
-
-    /**
      * 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
@@ -1284,7 +1084,7 @@
      * <p>
      * Note that this <em>does not</em> perform signature verification; that
      * must be done separately in
-     * {@link ApkParseUtils#collectCertificates(AndroidPackage, boolean)}.
+     * {@link #collectCertificates(Package, boolean)} .
      */
     private Package parseClusterPackage(File packageDir, int flags) throws PackageParserException {
         final PackageLite lite = parseClusterPackageLite(packageDir, 0);
@@ -1346,7 +1146,7 @@
      * <p>
      * Note that this <em>does not</em> perform signature verification; that
      * must be done separately in
-     * {@link ApkParseUtils#collectCertificates(AndroidPackage, boolean)}.
+     * {@link #collectCertificates(Package, boolean)}.
      */
     @UnsupportedAppUsage
     public Package parseMonolithicPackage(File apkFile, int flags) throws PackageParserException {
diff --git a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
index 9087f42..4c6da03 100644
--- a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
+++ b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
@@ -50,7 +50,7 @@
 /** @hide */
 public class ApkLiteParseUtils {
 
-    private static final String TAG = ApkParseUtils.TAG;
+    private static final String TAG = ParsingPackageUtils.TAG;
 
     // TODO(b/135203078): Consolidate constants
     private static final int DEFAULT_MIN_SDK_VERSION = 1;
@@ -235,7 +235,7 @@
                 final boolean skipVerify = (flags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0;
                 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates");
                 try {
-                    signingDetails = ApkParseUtils.collectCertificates(apkFile.getAbsolutePath(),
+                    signingDetails = ParsingPackageUtils.collectCertificates(apkFile.getAbsolutePath(),
                             skipVerify, false, PackageParser.SigningDetails.UNKNOWN,
                             DEFAULT_TARGET_SDK_VERSION);
                 } finally {
diff --git a/core/java/android/content/pm/parsing/ComponentParseUtils.java b/core/java/android/content/pm/parsing/ComponentParseUtils.java
index 6852a8c..4895396 100644
--- a/core/java/android/content/pm/parsing/ComponentParseUtils.java
+++ b/core/java/android/content/pm/parsing/ComponentParseUtils.java
@@ -82,7 +82,7 @@
  */
 public class ComponentParseUtils {
 
-    private static final String TAG = ApkParseUtils.TAG;
+    private static final String TAG = ParsingUtils.TAG;
 
     // TODO(b/135203078): None of this class's subclasses do anything. Remove in favor of base?
     public static class ParsedIntentInfo extends IntentFilter {
@@ -315,7 +315,7 @@
         // TODO(b/135203078): Make subclass that contains these fields only for the necessary
         //  subtypes
         protected boolean enabled = true;
-        protected boolean directBootAware;
+        public boolean directBootAware;
         public int flags;
 
         private String packageName;
@@ -1460,7 +1460,7 @@
                 outError[0] = tag + " does not specify android:name";
                 return null;
             } else {
-                String className = ApkParseUtils.buildClassName(packageName, name);
+                String className = ParsingUtils.buildClassName(packageName, name);
                 if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) {
                     outError[0] = tag + " invalid android:name";
                     return null;
@@ -1537,7 +1537,7 @@
                     R.styleable.AndroidManifestActivity_parentActivityName,
                     Configuration.NATIVE_CONFIG_VERSION);
             if (parentName != null) {
-                String parentClassName = ApkParseUtils.buildClassName(packageName, parentName);
+                String parentClassName = ParsingUtils.buildClassName(packageName, parentName);
                 if (parentClassName == null) {
                     Log.e(TAG,
                             "Activity " + result.className
@@ -1856,9 +1856,8 @@
                     parsingPackage.addPreferredActivityFilter(intentInfo);
                 }
             } else if (parser.getName().equals("meta-data")) {
-                if ((result.metaData = ApkParseUtils.parseMetaData(parsingPackage, res, parser,
-                        result.metaData,
-                        outError)) == null) {
+                if ((result.metaData = ParsingPackageUtils.parseMetaData(parsingPackage, res,
+                        parser, result.metaData, outError)) == null) {
                     return null;
                 }
             } else if (!receiver && parser.getName().equals("layout")) {
@@ -1969,7 +1968,7 @@
                 outError[0] = "<service> does not specify android:name";
                 return null;
             } else {
-                String className = ApkParseUtils.buildClassName(packageName, name);
+                String className = ParsingUtils.buildClassName(packageName, name);
                 if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) {
                     outError[0] = "<service> invalid android:name";
                     return null;
@@ -2099,7 +2098,7 @@
             }
         }
 
-        if (parsingPackage.cantSaveState()) {
+        if (parsingPackage.isCantSaveState()) {
             // 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())) {
@@ -2132,9 +2131,8 @@
                 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) {
+                if ((result.metaData = ParsingPackageUtils.parseMetaData(parsingPackage, res,
+                        parser, result.metaData, outError)) == null) {
                     return null;
                 }
             } else {
@@ -2182,7 +2180,7 @@
                 outError[0] = "<provider> does not specify android:name";
                 return null;
             } else {
-                String className = ApkParseUtils.buildClassName(packageName, name);
+                String className = ParsingUtils.buildClassName(packageName, name);
                 if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) {
                     outError[0] = "<provider> invalid android:name";
                     return null;
@@ -2413,7 +2411,7 @@
                 outInfo.intents.add(intent);
 
             } else if (parser.getName().equals("meta-data")) {
-                Bundle metaData = ApkParseUtils.parseMetaData(parsingPackage, res, parser,
+                Bundle metaData = ParsingPackageUtils.parseMetaData(parsingPackage, res, parser,
                         outInfo.metaData, outError);
                 if (metaData == null) {
                     return false;
@@ -2607,7 +2605,7 @@
         }
 
         String packageName = parsingPackage.getPackageName();
-        targetActivity = ApkParseUtils.buildClassName(packageName, targetActivity);
+        targetActivity = ParsingUtils.buildClassName(packageName, targetActivity);
         if (targetActivity == null) {
             outError[0] = "Empty class name in package " + packageName;
             sa.recycle();
@@ -2664,7 +2662,7 @@
         result.requestedVrComponent = target.requestedVrComponent;
         result.directBootAware = target.directBootAware;
 
-        result.setProcessName(parsingPackage.getAppInfoProcessName(), target.getProcessName());
+        result.setProcessName(parsingPackage.getProcessName(), 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.
@@ -2686,7 +2684,7 @@
             outError[0] = "<activity-alias> does not specify android:name";
             return null;
         } else {
-            String className = ApkParseUtils.buildClassName(packageName, name);
+            String className = ParsingUtils.buildClassName(packageName, name);
             if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) {
                 outError[0] = "<activity-alias> invalid android:name";
                 return null;
@@ -2751,7 +2749,7 @@
                 R.styleable.AndroidManifestActivityAlias_parentActivityName,
                 Configuration.NATIVE_CONFIG_VERSION);
         if (parentName != null) {
-            String parentClassName = ApkParseUtils.buildClassName(result.getPackageName(),
+            String parentClassName = ParsingUtils.buildClassName(result.getPackageName(),
                     parentName);
             if (parentClassName == null) {
                 Log.e(TAG, "Activity alias " + result.className +
@@ -2811,9 +2809,8 @@
                     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) {
+                if ((result.metaData = ParsingPackageUtils.parseMetaData(parsingPackage, res,
+                        parser, result.metaData, outError)) == null) {
                     return null;
                 }
             } else {
@@ -2935,7 +2932,7 @@
                 outError[0] = "<permission> does not specify android:name";
                 return null;
             } else {
-                String className = ApkParseUtils.buildClassName(packageName, name);
+                String className = ParsingUtils.buildClassName(packageName, name);
                 if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) {
                     outError[0] = "<permission> invalid android:name";
                     return null;
@@ -3073,7 +3070,7 @@
                 outError[0] = "<permission-tree> does not specify android:name";
                 return null;
             } else {
-                String className = ApkParseUtils.buildClassName(packageName, name);
+                String className = ParsingUtils.buildClassName(packageName, name);
                 if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) {
                     outError[0] = "<permission-tree> invalid android:name";
                     return null;
@@ -3163,7 +3160,7 @@
                 outError[0] = "<permission> does not specify android:name";
                 return null;
             } else {
-                String className = ApkParseUtils.buildClassName(packageName, name);
+                String className = ParsingUtils.buildClassName(packageName, name);
                 if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) {
                     outError[0] = "<permission> invalid android:name";
                     return null;
@@ -3262,7 +3259,7 @@
                 outError[0] = "<instrumentation> does not specify android:name";
                 return null;
             } else {
-                String className = ApkParseUtils.buildClassName(packageName, name);
+                String className = ParsingUtils.buildClassName(packageName, name);
                 if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) {
                     outError[0] = "<instrumentation> invalid android:name";
                     return null;
@@ -3764,8 +3761,8 @@
             }
 
             if (parser.getName().equals("meta-data")) {
-                if ((outInfo.metaData = ApkParseUtils.parseMetaData(parsingPackage, res, parser,
-                        outInfo.metaData, outError)) == null) {
+                if ((outInfo.metaData = ParsingPackageUtils.parseMetaData(parsingPackage, res,
+                        parser, outInfo.metaData, outError)) == null) {
                     return false;
                 }
             } else {
diff --git a/core/java/android/content/pm/parsing/PackageInfoUtils.java b/core/java/android/content/pm/parsing/PackageInfoUtils.java
deleted file mode 100644
index 72df189..0000000
--- a/core/java/android/content/pm/parsing/PackageInfoUtils.java
+++ /dev/null
@@ -1,595 +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 android.content.pm.parsing;
-
-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.ProcessInfo;
-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.util.ArrayMap;
-import android.util.ArraySet;
-
-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), pkg, 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;
-    }
-
-    @Nullable
-    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;
-        }
-
-        // Make shallow copy so we can store the metadata/libraries safely
-        ApplicationInfo ai = pkg.toAppInfoWithoutState();
-        ai.initForUser(userId);
-        if ((flags & PackageManager.GET_META_DATA) == 0) {
-            ai.metaData = null;
-        }
-        if ((flags & PackageManager.GET_SHARED_LIBRARY_FILES) == 0) {
-            ai.sharedLibraryFiles = null;
-            ai.sharedLibraryInfos = null;
-        }
-        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);
-        }
-        // 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.preferMinimalPostProcessing = a.preferMinimalPostProcessing;
-        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);
-        }
-        // 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);
-        }
-        // 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,
-            AndroidPackage pkg, @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 = pkg.getBaseCodePath();
-        ii.publicSourceDir = pkg.getBaseCodePath();
-        ii.splitNames = pkg.getSplitNames();
-        ii.splitSourceDirs = pkg.getSplitCodePaths();
-        ii.splitPublicSourceDirs = pkg.getSplitCodePaths();
-        ii.splitDependencies = pkg.getSplitDependencies();
-        ii.dataDir = pkg.getDataDir();
-        ii.deviceProtectedDataDir = pkg.getDeviceProtectedDataDir();
-        ii.credentialProtectedDataDir = pkg.getCredentialProtectedDataDir();
-        ii.primaryCpuAbi = pkg.getPrimaryCpuAbi();
-        ii.secondaryCpuAbi = pkg.getSecondaryCpuAbi();
-        ii.nativeLibraryDir = pkg.getNativeLibraryDir();
-        ii.secondaryNativeLibraryDir = pkg.getSecondaryNativeLibraryDir();
-
-        if ((flags & PackageManager.GET_META_DATA) == 0) {
-            return ii;
-        }
-        ii.metaData = i.metaData;
-        return ii;
-    }
-
-    public static ArrayMap<String, ProcessInfo> generateProcessInfo(
-            ArrayMap<String, ComponentParseUtils.ParsedProcess> procs,
-            @PackageManager.ComponentInfoFlags int flags) {
-        if (procs == null) {
-            return null;
-        }
-
-        final int numProcs = procs.size();
-        ArrayMap<String, ProcessInfo> retProcs = new ArrayMap(numProcs);
-        for (int i = 0; i < numProcs; i++) {
-            ComponentParseUtils.ParsedProcess proc = procs.valueAt(i);
-            retProcs.put(proc.name, new ProcessInfo(proc.name,
-                    proc.deniedPermissions != null
-                            ? new ArraySet<>(proc.deniedPermissions) : null));
-        }
-        return retProcs;
-    }
-
-    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.descriptionRes = pg.descriptionRes;
-        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 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.getAllOverlayPaths();
-        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/PackageInfoWithoutStateUtils.java b/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
new file mode 100644
index 0000000..0e833b2
--- /dev/null
+++ b/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
@@ -0,0 +1,691 @@
+/*
+ * Copyright (C) 2020 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.CheckResult;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.apex.ApexInfo;
+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.ParsedComponent;
+import android.content.pm.parsing.ComponentParseUtils.ParsedInstrumentation;
+import android.content.pm.parsing.ComponentParseUtils.ParsedMainComponent;
+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.Environment;
+import android.os.UserHandle;
+
+import com.android.internal.util.ArrayUtils;
+
+import libcore.util.EmptyArray;
+
+import java.io.File;
+import java.util.Collections;
+import java.util.Set;
+
+/** @hide **/
+public class PackageInfoWithoutStateUtils {
+
+    @Nullable
+    public static PackageInfo generate(ParsingPackageRead pkg, int[] gids,
+            @PackageManager.PackageInfoFlags int flags, long firstInstallTime, long lastUpdateTime,
+            Set<String> grantedPermissions, PackageUserState state, int userId) {
+        return generateWithComponents(pkg, gids, flags, firstInstallTime, lastUpdateTime, grantedPermissions,
+                state, userId, null);
+    }
+
+    @Nullable
+    public static PackageInfo generate(ParsingPackageRead pkg, ApexInfo apexInfo, int flags) {
+        return generateWithComponents(pkg, EmptyArray.INT, flags, 0, 0, Collections.emptySet(),
+                new PackageUserState(), UserHandle.getCallingUserId(), apexInfo);
+    }
+
+    @Nullable
+    private static PackageInfo generateWithComponents(ParsingPackageRead pkg, int[] gids,
+            @PackageManager.PackageInfoFlags int flags, long firstInstallTime, long lastUpdateTime,
+            Set<String> grantedPermissions, PackageUserState state, int userId,
+            @Nullable ApexInfo apexInfo) {
+        ApplicationInfo applicationInfo = generateApplicationInfo(pkg, flags, state, userId);
+        if (applicationInfo == null) {
+            return null;
+        }
+        PackageInfo info = generateWithoutComponents(pkg, gids, flags, firstInstallTime,
+                lastUpdateTime, grantedPermissions, state, userId, apexInfo, applicationInfo);
+
+        if (info == null) {
+            return null;
+        }
+
+        if ((flags & PackageManager.GET_ACTIVITIES) != 0) {
+            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(false, pkg.isEnabled(), a, flags)) {
+                        if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(
+                                a.getName())) {
+                            continue;
+                        }
+                        res[num++] = generateActivityInfo(pkg, a, flags, state,
+                                applicationInfo, userId);
+                    }
+                }
+                info.activities = ArrayUtils.trimToSize(res, num);
+            }
+        }
+        if ((flags & PackageManager.GET_RECEIVERS) != 0) {
+            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(false, pkg.isEnabled(), a, flags)) {
+                        res[num++] = generateActivityInfo(pkg, a, flags, state,
+                                applicationInfo, userId);
+                    }
+                }
+                info.receivers = ArrayUtils.trimToSize(res, num);
+            }
+        }
+        if ((flags & PackageManager.GET_SERVICES) != 0) {
+            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 ParsedService s = pkg.getServices().get(i);
+                    if (state.isMatch(false, pkg.isEnabled(), s, flags)) {
+                        res[num++] = generateServiceInfo(pkg, s, flags, state,
+                                applicationInfo, userId);
+                    }
+                }
+                info.services = ArrayUtils.trimToSize(res, num);
+            }
+        }
+        if ((flags & PackageManager.GET_PROVIDERS) != 0) {
+            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 ParsedProvider pr = pkg.getProviders()
+                            .get(i);
+                    if (state.isMatch(false, pkg.isEnabled(), pr, flags)) {
+                        res[num++] = generateProviderInfo(pkg, pr, flags, state,
+                                applicationInfo, userId);
+                    }
+                }
+                info.providers = ArrayUtils.trimToSize(res, num);
+            }
+        }
+        if ((flags & PackageManager.GET_INSTRUMENTATION) != 0) {
+            int N = pkg.getInstrumentations().size();
+            if (N > 0) {
+                info.instrumentation = new InstrumentationInfo[N];
+                for (int i = 0; i < N; i++) {
+                    info.instrumentation[i] = generateInstrumentationInfo(
+                            pkg.getInstrumentations().get(i), pkg, flags, userId);
+                }
+            }
+        }
+
+        return info;
+    }
+
+    @Nullable
+    public static PackageInfo generateWithoutComponents(ParsingPackageRead pkg, int[] gids,
+            @PackageManager.PackageInfoFlags int flags, long firstInstallTime, long lastUpdateTime,
+            Set<String> grantedPermissions, PackageUserState state, int userId,
+            @Nullable ApexInfo apexInfo, @NonNull ApplicationInfo applicationInfo) {
+        if (!checkUseInstalled(pkg, state, flags)) {
+            return null;
+        }
+
+        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();
+        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().size();
+            if (size > 0) {
+                pi.configPreferences = new ConfigurationInfo[size];
+                pkg.getConfigPreferences().toArray(pi.configPreferences);
+            }
+            size = pkg.getReqFeatures().size();
+            if (size > 0) {
+                pi.reqFeatures = new FeatureInfo[size];
+                pkg.getReqFeatures().toArray(pi.reqFeatures);
+            }
+            size = pkg.getFeatureGroups().size();
+            if (size > 0) {
+                pi.featureGroups = new FeatureGroupInfo[size];
+                pkg.getFeatureGroups().toArray(pi.featureGroups);
+            }
+        }
+        if ((flags & PackageManager.GET_PERMISSIONS) != 0) {
+            int size = ArrayUtils.size(pkg.getPermissions());
+            if (size > 0) {
+                pi.permissions = new PermissionInfo[size];
+                for (int i = 0; i < size; i++) {
+                    pi.permissions[i] = generatePermissionInfo(pkg.getPermissions().get(i),
+                            flags);
+                }
+            }
+            size = pkg.getRequestedPermissions().size();
+            if (size > 0) {
+                pi.requestedPermissions = new String[size];
+                pi.requestedPermissionsFlags = new int[size];
+                for (int i = 0; i < size; 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;
+                    }
+                }
+            }
+        }
+
+        if (apexInfo != null) {
+            File apexFile = new File(apexInfo.modulePath);
+
+            pi.applicationInfo.sourceDir = apexFile.getPath();
+            pi.applicationInfo.publicSourceDir = apexFile.getPath();
+            if (apexInfo.isFactory) {
+                pi.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
+            } else {
+                pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_SYSTEM;
+            }
+            if (apexInfo.isActive) {
+                pi.applicationInfo.flags |= ApplicationInfo.FLAG_INSTALLED;
+            } else {
+                pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_INSTALLED;
+            }
+            pi.isApex = true;
+        }
+
+        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;
+    }
+
+    @Nullable
+    public static ApplicationInfo generateApplicationInfo(ParsingPackageRead pkg,
+            @PackageManager.ApplicationInfoFlags int flags, PackageUserState state, int userId) {
+        if (pkg == null) {
+            return null;
+        }
+
+        if (!checkUseInstalled(pkg, state, flags)) {
+            return null;
+        }
+
+        // Make shallow copy so we can store the metadata/libraries safely
+        ApplicationInfo ai = pkg.toAppInfoWithoutState();
+        // Init handles data directories
+        // TODO(b/135203078): Consolidate the data directory logic, remove initForUser
+        ai.initForUser(userId);
+
+        ai.flags = appInfoFlags(pkg);
+        ai.privateFlags = appInfoPrivateFlags(pkg);
+
+        if ((flags & PackageManager.GET_META_DATA) == 0) {
+            ai.metaData = null;
+        }
+        if ((flags & PackageManager.GET_SHARED_LIBRARY_FILES) == 0) {
+            ai.sharedLibraryFiles = null;
+            ai.sharedLibraryInfos = null;
+        }
+
+        // CompatibilityMode is global state.
+        if (!PackageParser.sCompatibilityModeEnabled) {
+            ai.disableCompatibilityMode();
+        }
+
+        ai.flags |= flag(state.stopped, ApplicationInfo.FLAG_STOPPED)
+                | flag(state.installed, ApplicationInfo.FLAG_INSTALLED)
+                | flag(state.suspended, ApplicationInfo.FLAG_SUSPENDED);
+        ai.privateFlags |= flag(state.instantApp, ApplicationInfo.PRIVATE_FLAG_INSTANT)
+                | flag(state.virtualPreload, ApplicationInfo.PRIVATE_FLAG_VIRTUAL_PRELOAD)
+                | flag(state.hidden, 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.getOverlayPaths();
+
+        return ai;
+    }
+
+    @Nullable
+    public static ActivityInfo generateActivityInfo(ParsingPackageRead pkg, ParsedActivity a,
+            @PackageManager.ComponentInfoFlags int flags, PackageUserState state,
+            @Nullable ApplicationInfo applicationInfo, int userId) {
+        if (a == null) return null;
+        if (!checkUseInstalled(pkg, state, flags)) {
+            return null;
+        }
+        if (applicationInfo == null) {
+            applicationInfo = generateApplicationInfo(pkg, flags, state, userId);
+        }
+        // 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.preferMinimalPostProcessing = a.preferMinimalPostProcessing;
+        ai.windowLayout = a.windowLayout;
+        ai.metaData = a.getMetaData();
+        ai.applicationInfo = applicationInfo;
+        return ai;
+    }
+
+    @Nullable
+    public static ActivityInfo generateActivityInfo(ParsingPackageRead pkg, ParsedActivity a,
+            @PackageManager.ComponentInfoFlags int flags, PackageUserState state, int userId) {
+        return generateActivityInfo(pkg, a, flags, state, null, userId);
+    }
+
+    @Nullable
+    public static ServiceInfo generateServiceInfo(ParsingPackageRead pkg, ParsedService s,
+            @PackageManager.ComponentInfoFlags int flags, PackageUserState state,
+            @Nullable ApplicationInfo applicationInfo, int userId) {
+        if (s == null) return null;
+        if (!checkUseInstalled(pkg, state, flags)) {
+            return null;
+        }
+        if (applicationInfo == null) {
+            applicationInfo = generateApplicationInfo(pkg, flags, state, userId);
+        }
+        // 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.getMetaData();
+        si.permission = s.getPermission();
+        si.processName = s.getProcessName();
+        si.mForegroundServiceType = s.foregroundServiceType;
+        si.applicationInfo = applicationInfo;
+        return si;
+    }
+
+    @Nullable
+    public static ServiceInfo generateServiceInfo(ParsingPackageRead pkg, ParsedService s,
+            @PackageManager.ComponentInfoFlags int flags, PackageUserState state, int userId) {
+        return generateServiceInfo(pkg, s, flags, state, null, userId);
+    }
+
+    @Nullable
+    public static ProviderInfo generateProviderInfo(ParsingPackageRead pkg, ParsedProvider p,
+            @PackageManager.ComponentInfoFlags int flags, PackageUserState state,
+            @Nullable ApplicationInfo applicationInfo, int userId) {
+        if (p == null) return null;
+        if (!checkUseInstalled(pkg, state, flags)) {
+            return null;
+        }
+        if (applicationInfo == null) {
+            applicationInfo = generateApplicationInfo(pkg, flags, state, userId);
+        }
+        // Make shallow copies so we can store the metadata safely
+        ProviderInfo pi = new ProviderInfo();
+        assignSharedFieldsForComponentInfo(pi, p);
+        pi.exported = p.isExported();
+        pi.flags = p.getFlags();
+        pi.processName = p.getProcessName();
+        pi.authority = p.getAuthority();
+        pi.isSyncable = p.isSyncable();
+        pi.readPermission = p.getReadPermission();
+        pi.writePermission = p.getWritePermission();
+        pi.grantUriPermissions = p.isGrantUriPermissions();
+        pi.forceUriPermissions = p.isForceUriPermissions();
+        pi.multiprocess = p.isMultiProcess();
+        pi.initOrder = p.getInitOrder();
+        pi.uriPermissionPatterns = p.getUriPermissionPatterns();
+        pi.pathPermissions = p.getPathPermissions();
+        pi.metaData = p.getMetaData();
+        if ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) == 0) {
+            pi.uriPermissionPatterns = null;
+        }
+        pi.applicationInfo = applicationInfo;
+        return pi;
+    }
+
+    @Nullable
+    public static ProviderInfo generateProviderInfo(ParsingPackageRead pkg, ParsedProvider p,
+            @PackageManager.ComponentInfoFlags int flags, PackageUserState state, int userId) {
+        return generateProviderInfo(pkg, p, flags, state, null, userId);
+    }
+
+    @Nullable
+    public static InstrumentationInfo generateInstrumentationInfo(ParsedInstrumentation i,
+            ParsingPackageRead pkg, @PackageManager.ComponentInfoFlags int flags, int userId) {
+        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 = pkg.getBaseCodePath();
+        ii.publicSourceDir = pkg.getBaseCodePath();
+        ii.splitNames = pkg.getSplitNames();
+        ii.splitSourceDirs = pkg.getSplitCodePaths();
+        ii.splitPublicSourceDirs = pkg.getSplitCodePaths();
+        ii.splitDependencies = pkg.getSplitDependencies();
+        ii.dataDir = getDataDir(pkg, UserHandle.myUserId()).getAbsolutePath();
+        ii.deviceProtectedDataDir = getDeviceProtectedDataDir(pkg, userId)
+                .getAbsolutePath();
+        ii.credentialProtectedDataDir = getCredentialProtectedDataDir(pkg,
+                userId).getAbsolutePath();
+
+        if ((flags & PackageManager.GET_META_DATA) == 0) {
+            return ii;
+        }
+        ii.metaData = i.getMetaData();
+        return ii;
+    }
+
+    @Nullable
+    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.getMetaData();
+        return pi;
+    }
+
+    @Nullable
+    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.descriptionRes = pg.descriptionRes;
+        pgi.priority = pg.priority;
+        pgi.requestRes = pg.requestRes;
+        pgi.flags = pg.flags;
+
+        if ((flags & PackageManager.GET_META_DATA) == 0) {
+            return pgi;
+        }
+        pgi.metaData = pg.getMetaData();
+        return pgi;
+    }
+
+    private static void assignSharedFieldsForComponentInfo(@NonNull ComponentInfo componentInfo,
+            @NonNull ParsedMainComponent mainComponent) {
+        assignSharedFieldsForPackageItemInfo(componentInfo, mainComponent);
+        componentInfo.descriptionRes = mainComponent.descriptionRes;
+        componentInfo.directBootAware = mainComponent.isDirectBootAware();
+        componentInfo.enabled = mainComponent.isEnabled();
+        componentInfo.splitName = mainComponent.getSplitName();
+    }
+
+    private static void assignSharedFieldsForPackageItemInfo(
+            @NonNull PackageItemInfo packageItemInfo, @NonNull ParsedComponent component) {
+        packageItemInfo.nonLocalizedLabel = component.nonLocalizedLabel;
+        packageItemInfo.icon = component.icon;
+
+        packageItemInfo.banner = component.banner;
+        packageItemInfo.labelRes = component.labelRes;
+        packageItemInfo.logo = component.logo;
+        packageItemInfo.name = component.getName();
+        packageItemInfo.packageName = component.getPackageName();
+    }
+
+    @CheckResult
+    private static int flag(boolean hasFlag, int flag) {
+        if (hasFlag) {
+            return flag;
+        } else {
+            return 0;
+        }
+    }
+
+    /** @see ApplicationInfo#flags */
+    public static int appInfoFlags(ParsingPackageRead pkg) {
+        // @formatter:off
+        return flag(pkg.isExternalStorage(), ApplicationInfo.FLAG_EXTERNAL_STORAGE)
+                | flag(pkg.isBaseHardwareAccelerated(), ApplicationInfo.FLAG_HARDWARE_ACCELERATED)
+                | flag(pkg.isAllowBackup(), ApplicationInfo.FLAG_ALLOW_BACKUP)
+                | flag(pkg.isKillAfterRestore(), ApplicationInfo.FLAG_KILL_AFTER_RESTORE)
+                | flag(pkg.isRestoreAnyVersion(), ApplicationInfo.FLAG_RESTORE_ANY_VERSION)
+                | flag(pkg.isFullBackupOnly(), ApplicationInfo.FLAG_FULL_BACKUP_ONLY)
+                | flag(pkg.isPersistent(), ApplicationInfo.FLAG_PERSISTENT)
+                | flag(pkg.isDebuggable(), ApplicationInfo.FLAG_DEBUGGABLE)
+                | flag(pkg.isVmSafeMode(), ApplicationInfo.FLAG_VM_SAFE_MODE)
+                | flag(pkg.isHasCode(), ApplicationInfo.FLAG_HAS_CODE)
+                | flag(pkg.isAllowTaskReparenting(), ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING)
+                | flag(pkg.isAllowClearUserData(), ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA)
+                | flag(pkg.isLargeHeap(), ApplicationInfo.FLAG_LARGE_HEAP)
+                | flag(pkg.isUsesCleartextTraffic(), ApplicationInfo.FLAG_USES_CLEARTEXT_TRAFFIC)
+                | flag(pkg.isSupportsRtl(), ApplicationInfo.FLAG_SUPPORTS_RTL)
+                | flag(pkg.isTestOnly(), ApplicationInfo.FLAG_TEST_ONLY)
+                | flag(pkg.isMultiArch(), ApplicationInfo.FLAG_MULTIARCH)
+                | flag(pkg.isExtractNativeLibs(), ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS)
+                | flag(pkg.isGame(), ApplicationInfo.FLAG_IS_GAME)
+                | flag(pkg.isSupportsSmallScreens(), ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS)
+                | flag(pkg.isSupportsNormalScreens(), ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS)
+                | flag(pkg.isSupportsLargeScreens(), ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS)
+                | flag(pkg.isSupportsExtraLargeScreens(), ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS)
+                | flag(pkg.isResizeable(), ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS)
+                | flag(pkg.isAnyDensity(), ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES);
+        // @formatter:on
+    }
+
+    /** @see ApplicationInfo#privateFlags */
+    public static int appInfoPrivateFlags(ParsingPackageRead pkg) {
+        // @formatter:off
+        int privateFlags = flag(pkg.isStaticSharedLibrary(), ApplicationInfo.PRIVATE_FLAG_STATIC_SHARED_LIBRARY)
+                | flag(pkg.isOverlay(), ApplicationInfo.PRIVATE_FLAG_IS_RESOURCE_OVERLAY)
+                | flag(pkg.isIsolatedSplitLoading(), ApplicationInfo.PRIVATE_FLAG_ISOLATED_SPLIT_LOADING)
+                | flag(pkg.isHasDomainUrls(), ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS)
+                | flag(pkg.isProfileableByShell(), ApplicationInfo.PRIVATE_FLAG_PROFILEABLE_BY_SHELL)
+                | flag(pkg.isBackupInForeground(), ApplicationInfo.PRIVATE_FLAG_BACKUP_IN_FOREGROUND)
+                | flag(pkg.isUseEmbeddedDex(), ApplicationInfo.PRIVATE_FLAG_USE_EMBEDDED_DEX)
+                | flag(pkg.isDefaultToDeviceProtectedStorage(), ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE)
+                | flag(pkg.isDirectBootAware(), ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE)
+                | flag(pkg.isPartiallyDirectBootAware(), ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE)
+                | flag(pkg.isAllowClearUserDataOnFailedRestore(), ApplicationInfo.PRIVATE_FLAG_ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE)
+                | flag(pkg.isAllowAudioPlaybackCapture(), ApplicationInfo.PRIVATE_FLAG_ALLOW_AUDIO_PLAYBACK_CAPTURE)
+                | flag(pkg.isRequestLegacyExternalStorage(), ApplicationInfo.PRIVATE_FLAG_REQUEST_LEGACY_EXTERNAL_STORAGE)
+                | flag(pkg.isUsesNonSdkApi(), ApplicationInfo.PRIVATE_FLAG_USES_NON_SDK_API)
+                | flag(pkg.isHasFragileUserData(), ApplicationInfo.PRIVATE_FLAG_HAS_FRAGILE_USER_DATA)
+                | flag(pkg.isCantSaveState(), ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE)
+                | flag(pkg.isResizeableActivityViaSdkVersion(), ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION)
+                | flag(pkg.isAllowNativeHeapPointerTagging(), ApplicationInfo.PRIVATE_FLAG_ALLOW_NATIVE_HEAP_POINTER_TAGGING);
+        // @formatter:on
+
+        Boolean resizeableActivity = pkg.getResizeableActivity();
+        if (resizeableActivity != null) {
+            if (resizeableActivity) {
+                privateFlags |= ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE;
+            } else {
+                privateFlags |= ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE;
+            }
+        }
+
+        return privateFlags;
+    }
+
+    private static boolean checkUseInstalled(ParsingPackageRead pkg, PackageUserState state,
+            @PackageManager.PackageInfoFlags int flags) {
+        // If available for the target user
+        return state.isAvailable(flags);
+    }
+
+
+    @NonNull
+    public static File getDataDir(ParsingPackageRead pkg, int userId) {
+        if ("android".equals(pkg.getPackageName())) {
+            return Environment.getDataSystemDirectory();
+        }
+
+        if (pkg.isDefaultToDeviceProtectedStorage()
+                && PackageManager.APPLY_DEFAULT_TO_DEVICE_PROTECTED_STORAGE) {
+            return getDeviceProtectedDataDir(pkg, userId);
+        } else {
+            return getCredentialProtectedDataDir(pkg, userId);
+        }
+    }
+
+    @NonNull
+    public static File getDeviceProtectedDataDir(ParsingPackageRead pkg, int userId) {
+        return Environment.getDataUserDePackageDirectory(pkg.getVolumeUuid(), userId,
+                pkg.getPackageName());
+    }
+
+    @NonNull
+    public static File getCredentialProtectedDataDir(ParsingPackageRead pkg, int userId) {
+        return Environment.getDataUserCePackageDirectory(pkg.getVolumeUuid(), userId,
+                pkg.getPackageName());
+    }
+}
diff --git a/core/java/android/content/pm/parsing/ParsingPackageImpl.java b/core/java/android/content/pm/parsing/ParsingPackageImpl.java
index 840e1af..f046d383 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageImpl.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageImpl.java
@@ -61,7 +61,7 @@
 import com.android.internal.util.Parcelling.BuiltIn.ForInternedString;
 import com.android.internal.util.Parcelling.BuiltIn.ForInternedStringArray;
 import com.android.internal.util.Parcelling.BuiltIn.ForInternedStringList;
-import com.android.internal.util.Parcelling.BuiltIn.ForInternedStringMap;
+import com.android.internal.util.Parcelling.BuiltIn.ForInternedStringValueMap;
 import com.android.internal.util.Parcelling.BuiltIn.ForInternedStringSet;
 
 import java.security.PublicKey;
@@ -159,7 +159,7 @@
     private int overlayPriority;
     private boolean overlayIsStatic;
     @NonNull
-    @DataClass.ParcelWith(ForInternedStringMap.class)
+    @DataClass.ParcelWith(ForInternedStringValueMap.class)
     private Map<String, String> overlayables = emptyMap();
 
     @Nullable
diff --git a/core/java/android/content/pm/parsing/ApkParseUtils.java b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
similarity index 97%
rename from core/java/android/content/pm/parsing/ApkParseUtils.java
rename to core/java/android/content/pm/parsing/ParsingPackageUtils.java
index 905794b..dd809f0f 100644
--- a/core/java/android/content/pm/parsing/ApkParseUtils.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
@@ -26,6 +26,7 @@
 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.DONUT;
 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;
@@ -99,10 +100,10 @@
 import java.util.StringTokenizer;
 
 /** @hide */
-public class ApkParseUtils {
+public class ParsingPackageUtils {
 
     // TODO(b/135203078): Consolidate log tags
-    static final String TAG = "PackageParsing";
+    public static final String TAG = "PackageParsing";
 
     /**
      * Parse the package at the given location. Automatically detects if the
@@ -114,7 +115,7 @@
      * 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)}.
+     * must be done separately in {@link #collectCertificates(ParsingPackageRead, 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
@@ -126,7 +127,7 @@
     public static ParsingPackage parsePackage(
             ParseInput parseInput,
             String[] separateProcesses,
-            PackageParser.Callback callback,
+            Callback callback,
             DisplayMetrics displayMetrics,
             boolean onlyCoreApps,
             File packageFile,
@@ -148,12 +149,12 @@
      * split names.
      * <p>
      * Note that this <em>does not</em> perform signature verification; that
-     * must be done separately in {@link #collectCertificates(ParsedPackage, boolean)}.
+     * must be done separately in {@link #collectCertificates(ParsingPackageRead, boolean)}.
      */
     private static ParsingPackage parseClusterPackage(
             ParseInput parseInput,
             String[] separateProcesses,
-            PackageParser.Callback callback,
+            Callback callback,
             DisplayMetrics displayMetrics,
             boolean onlyCoreApps,
             File packageDir,
@@ -184,7 +185,7 @@
             final AssetManager assets = assetLoader.getBaseAssetManager();
             final File baseApk = new File(lite.baseCodePath);
             ParsingPackage parsingPackage = parseBaseApk(parseInput, separateProcesses, callback,
-                    displayMetrics, baseApk, assets, flags);
+                    displayMetrics, baseApk, lite.codePath, assets, flags);
             if (parsingPackage == null) {
                 throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
                         "Failed to parse base APK: " + baseApk);
@@ -206,8 +207,7 @@
                 }
             }
 
-            return parsingPackage.setCodePath(lite.codePath)
-                    .setUse32BitAbi(lite.use32bitAbi);
+            return parsingPackage.setUse32BitAbi(lite.use32bitAbi);
         } finally {
             IoUtils.closeQuietly(assetLoader);
         }
@@ -217,12 +217,12 @@
      * 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)}.
+     * must be done separately in {@link #collectCertificates(ParsingPackageRead, boolean)}.
      */
     public static ParsingPackage parseMonolithicPackage(
             ParseInput parseInput,
             String[] separateProcesses,
-            PackageParser.Callback callback,
+            Callback callback,
             DisplayMetrics displayMetrics,
             boolean onlyCoreApps,
             File apkFile,
@@ -240,8 +240,8 @@
         final SplitAssetLoader assetLoader = new DefaultSplitAssetLoader(lite, flags);
         try {
             return parseBaseApk(parseInput, separateProcesses, callback,
-                    displayMetrics, apkFile, assetLoader.getBaseAssetManager(), flags)
-                    .setCodePath(apkFile.getCanonicalPath())
+                    displayMetrics, apkFile, apkFile.getCanonicalPath(),
+                    assetLoader.getBaseAssetManager(), flags)
                     .setUse32BitAbi(lite.use32bitAbi);
         } catch (IOException e) {
             throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
@@ -251,14 +251,9 @@
         }
     }
 
-    private static ParsingPackage parseBaseApk(
-            ParseInput parseInput,
-            String[] separateProcesses,
-            PackageParser.Callback callback,
-            DisplayMetrics displayMetrics,
-            File apkFile,
-            AssetManager assets,
-            int flags
+    private static ParsingPackage parseBaseApk(ParseInput parseInput, String[] separateProcesses,
+            Callback callback, DisplayMetrics displayMetrics, File apkFile,
+            String codePath, AssetManager assets, int flags
     ) throws PackageParserException {
         final String apkPath = apkFile.getAbsolutePath();
 
@@ -280,8 +275,8 @@
             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);
+            ParseResult result = parseBaseApk(parseInput, separateProcesses, callback, apkPath,
+                    codePath, res, parser, flags);
             if (!result.isSuccess()) {
                 throw new PackageParserException(result.getParseError(),
                         apkPath + " (at " + parser.getPositionDescription() + "): "
@@ -305,7 +300,6 @@
             }
 
             return pkg.setVolumeUuid(volumeUuid)
-                    .setApplicationVolumeUuid(volumeUuid)
                     .setSigningDetails(SigningDetails.UNKNOWN);
         } catch (PackageParserException e) {
             throw e;
@@ -372,14 +366,9 @@
      * @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
+    private static ParseResult parseBaseApk(ParseInput parseInput, String[] separateProcesses,
+            Callback callback, String apkPath, String codePath, Resources res,
+            XmlResourceParser parser, int flags
     ) throws XmlPullParserException, IOException {
         final String splitName;
         final String pkgName;
@@ -407,12 +396,8 @@
 
             boolean isCoreApp = parser.getAttributeBooleanValue(null, "coreApp", false);
 
-            ParsingPackage parsingPackage = PackageImpl.forParsing(
-                    pkgName,
-                    apkPath,
-                    manifestArray,
-                    isCoreApp
-            );
+            ParsingPackage parsingPackage = callback.startParsingPackage(pkgName, apkPath, codePath,
+                    manifestArray, isCoreApp);
 
             ParseResult result = parseBaseApkTags(parseInput, separateProcesses, callback,
                     parsingPackage, manifestArray, res, parser, flags);
@@ -645,7 +630,7 @@
                     // 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(),
+                            parsingPackage.getMetaData(),
                             outError);
                     if (appMetaData == null) {
                         return parseInput.error(
@@ -654,7 +639,7 @@
                         );
                     }
 
-                    parsingPackage.setAppMetaData(appMetaData);
+                    parsingPackage.setMetaData(appMetaData);
                     break;
                 case "uses-static-library":
                     ParseResult parseResult = parseUsesStaticLibrary(parseInput, parsingPackage,
@@ -727,7 +712,7 @@
     private static ParseResult parseBaseApkTags(
             ParseInput parseInput,
             String[] separateProcesses,
-            PackageParser.Callback callback,
+            Callback callback,
             ParsingPackage parsingPackage,
             TypedArray manifestArray,
             Resources res,
@@ -897,13 +882,23 @@
         // 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()) {
+        if (usesCompatibilityMode(parsingPackage)) {
             adjustPackageToBeUnresizeableAndUnpipable(parsingPackage);
         }
 
         return parseInput.success(parsingPackage);
     }
 
+    public static boolean usesCompatibilityMode(ParsingPackage pkg) {
+        return pkg.getTargetSdkVersion() < DONUT
+                || (!pkg.isSupportsSmallScreens()
+                && !pkg.isSupportsNormalScreens()
+                && !pkg.isSupportsLargeScreens()
+                && !pkg.isSupportsExtraLargeScreens()
+                && !pkg.isResizeable()
+                && !pkg.isAnyDensity());
+    }
+
     private static ParseResult parseUnknownTag(
             ParseInput parseInput,
             ParsingPackage parsingPackage,
@@ -1234,20 +1229,11 @@
                 );
             }
 
-            parsingPackage.setName(outInfoName);
+            parsingPackage.setClassName(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);
-            }
-        }
+        parsingPackage.setRoundIconRes(sa.getResourceId(roundIconRes, 0))
+                .setIconRes(sa.getResourceId(iconRes, 0));
 
         int logoVal = sa.getResourceId(logoRes, 0);
         if (logoVal != 0) {
@@ -1375,7 +1361,7 @@
             ParsingPackage parsingPackage,
             Resources res,
             XmlResourceParser parser,
-            PackageParser.Callback callback
+            Callback callback
     )
             throws XmlPullParserException, IOException {
         TypedArray sa = res.obtainAttributes(parser,
@@ -1854,7 +1840,7 @@
     public static ParseResult parseBaseApplication(
             ParseInput parseInput,
             String[] separateProcesses,
-            PackageParser.Callback callback,
+            Callback callback,
             ParsingPackage parsingPackage,
             Resources res,
             XmlResourceParser parser,
@@ -1893,11 +1879,6 @@
                 return result;
             }
 
-            String name = parsingPackage.getName();
-            if (name != null) {
-                parsingPackage.setClassName(name);
-            }
-
             String manageSpaceActivity = sa.getNonConfigurationString(
                     R.styleable.AndroidManifestApplication_manageSpaceActivity,
                     Configuration.NATIVE_CONFIG_VERSION);
@@ -2078,10 +2059,10 @@
                     R.styleable.AndroidManifestApplication_directBootAware, false));
 
             if (sa.hasValueOrEmpty(R.styleable.AndroidManifestApplication_resizeableActivity)) {
-                parsingPackage.setActivitiesResizeModeResizeable(sa.getBoolean(
+                parsingPackage.setResizeableActivity(sa.getBoolean(
                         R.styleable.AndroidManifestApplication_resizeableActivity, true));
             } else {
-                parsingPackage.setActivitiesResizeModeResizeableViaSdkVersion(
+                parsingPackage.setResizeableActivityViaSdkVersion(
                         parsingPackage.getTargetSdkVersion() >= Build.VERSION_CODES.N);
             }
 
@@ -2195,7 +2176,7 @@
             parsingPackage.setCrossProfile(
                     sa.getBoolean(R.styleable.AndroidManifestApplication_crossProfile, false));
 
-            parsingPackage.setIsGame(sa.getBoolean(
+            parsingPackage.setGame(sa.getBoolean(
                     R.styleable.AndroidManifestApplication_isGame, false));
 
             boolean cantSaveState = sa.getBoolean(
@@ -2334,7 +2315,7 @@
                     // 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(),
+                            parsingPackage.getMetaData(),
                             outError);
                     if (appMetaData == null) {
                         return parseInput.error(
@@ -2343,7 +2324,7 @@
                         );
                     }
 
-                    parsingPackage.setAppMetaData(appMetaData);
+                    parsingPackage.setMetaData(appMetaData);
                     break;
                 case "static-library":
                     sa = res.obtainAttributes(parser,
@@ -2728,7 +2709,7 @@
             // Use the application max aspect ration as default if set.
             maxAspectRatio = packageMaxAspectRatio;
         } else {
-            Bundle appMetaData = parsingPackage.getAppMetaData();
+            Bundle appMetaData = parsingPackage.getMetaData();
             if (appMetaData != null && appMetaData.containsKey(
                     PackageParser.METADATA_MAX_ASPECT_RATIO)) {
                 maxAspectRatio = appMetaData.getFloat(PackageParser.METADATA_MAX_ASPECT_RATIO,
@@ -2764,7 +2745,7 @@
      */
     private static void setMinAspectRatio(
             ParsingPackage parsingPackage,
-            PackageParser.Callback callback
+            Callback callback
     ) {
         final float minAspectRatio;
         float packageMinAspectRatio = parsingPackage.getMinAspectRatio();
@@ -2845,7 +2826,7 @@
         }
 
         parsingPackage
-                .setIsOverlay(true)
+                .setOverlay(true)
                 .setOverlayTarget(target)
                 .setOverlayTargetName(targetName)
                 .setOverlayCategory(category)
@@ -2907,7 +2888,7 @@
                         sa.getInteger(R.styleable.AndroidManifestSupportsScreens_normalScreens, 1))
                 .setSupportsLargeScreens(
                         sa.getInteger(R.styleable.AndroidManifestSupportsScreens_largeScreens, 1))
-                .setSupportsXLargeScreens(
+                .setSupportsExtraLargeScreens(
                         sa.getInteger(R.styleable.AndroidManifestSupportsScreens_xlargeScreens, 1))
                 .setResizeable(
                         sa.getInteger(R.styleable.AndroidManifestSupportsScreens_resizeable, 1))
@@ -2960,7 +2941,7 @@
                 R.styleable.AndroidManifestOriginalPackage_name,
                 0);
         if (!parsingPackage.getPackageName().equals(orig)) {
-            if (parsingPackage.getOriginalPackages() == null) {
+            if (parsingPackage.getOriginalPackages().isEmpty()) {
                 parsingPackage.setRealPackage(parsingPackage.getPackageName());
             }
             parsingPackage.addOriginalPackage(orig);
@@ -3186,36 +3167,36 @@
     }
 
     /**
-     * Collect certificates from all the APKs described in the given package,
-     * populating {@link AndroidPackageWrite#setSigningDetails(SigningDetails)}. Also asserts that
+     * Collect certificates from all the APKs described in the given package. Also asserts that
      * all APK contents are signed correctly and consistently.
      */
-    public static void collectCertificates(AndroidPackage pkg, boolean skipVerify)
+    public static SigningDetails collectCertificates(ParsingPackageRead pkg, boolean skipVerify)
             throws PackageParserException {
-        pkg.mutate().setSigningDetails(SigningDetails.UNKNOWN);
+        SigningDetails signingDetails = SigningDetails.UNKNOWN;
 
         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates");
         try {
-            pkg.mutate().setSigningDetails(collectCertificates(
+            signingDetails = collectCertificates(
                     pkg.getBaseCodePath(),
                     skipVerify,
                     pkg.isStaticSharedLibrary(),
-                    pkg.getSigningDetails(),
+                    signingDetails,
                     pkg.getTargetSdkVersion()
-            ));
+            );
 
             String[] splitCodePaths = pkg.getSplitCodePaths();
             if (!ArrayUtils.isEmpty(splitCodePaths)) {
                 for (int i = 0; i < splitCodePaths.length; i++) {
-                    pkg.mutate().setSigningDetails(collectCertificates(
+                    signingDetails = collectCertificates(
                             splitCodePaths[i],
                             skipVerify,
                             pkg.isStaticSharedLibrary(),
-                            pkg.getSigningDetails(),
+                            signingDetails,
                             pkg.getTargetSdkVersion()
-                    ));
+                    );
                 }
             }
+            return signingDetails;
         } finally {
             Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
         }
@@ -3346,4 +3327,15 @@
             return errorMessage;
         }
     }
+
+    /**
+     * Callback interface for retrieving information that may be needed while parsing
+     * a package.
+     */
+    public interface Callback {
+        boolean hasFeature(String feature);
+
+        ParsingPackage startParsingPackage(String packageName, String baseCodePath, String codePath,
+                TypedArray manifestArray, boolean isCoreApp);
+    }
 }
diff --git a/core/java/android/content/pm/parsing/ParsingUtils.java b/core/java/android/content/pm/parsing/ParsingUtils.java
new file mode 100644
index 0000000..3ce629d
--- /dev/null
+++ b/core/java/android/content/pm/parsing/ParsingUtils.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2020 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;
+
+/** @hide **/
+public class ParsingUtils {
+
+    // TODO(b/135203078): Consolidate log tags
+    public static final String TAG = "PackageParsing";
+
+    @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;
+    }
+}
diff --git a/core/java/com/android/internal/content/om/OverlayConfig.java b/core/java/com/android/internal/content/om/OverlayConfig.java
index f699eb8..ffa347c 100644
--- a/core/java/com/android/internal/content/om/OverlayConfig.java
+++ b/core/java/com/android/internal/content/om/OverlayConfig.java
@@ -19,7 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.pm.PackagePartitions;
-import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.ParsingPackageRead;
 import android.os.Build;
 import android.os.Process;
 import android.os.Trace;
@@ -36,7 +36,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Comparator;
-import java.util.function.Consumer;
+import java.util.function.BiConsumer;
 import java.util.function.Supplier;
 
 /**
@@ -71,10 +71,10 @@
      * Interface for providing information on scanned packages.
      * TODO(147840005): Remove this when android:isStatic and android:priority are fully deprecated
      */
-    public interface AndroidPackageProvider {
+    public interface PackageProvider {
 
         /** Performs the given action for each package. */
-        void forEachPackage(Consumer<AndroidPackage> p);
+        void forEachPackage(BiConsumer<ParsingPackageRead, Boolean> p);
     }
 
     private static final Comparator<ParsedConfiguration> sStaticOverlayComparator = (c1, c2) -> {
@@ -100,7 +100,7 @@
     @VisibleForTesting
     public OverlayConfig(@Nullable File rootDirectory,
             @Nullable Supplier<OverlayScanner> scannerFactory,
-            @Nullable AndroidPackageProvider packageProvider) {
+            @Nullable PackageProvider packageProvider) {
         Preconditions.checkArgument((scannerFactory == null) != (packageProvider == null),
                 "scannerFactory and packageProvider cannot be both null or both non-null");
 
@@ -208,7 +208,7 @@
      * {@link #getSystemInstance()} will return the initialized instance.
      */
     @NonNull
-    public static OverlayConfig initializeSystemInstance(AndroidPackageProvider packageProvider) {
+    public static OverlayConfig initializeSystemInstance(PackageProvider packageProvider) {
         if (Process.myUid() != Process.SYSTEM_UID) {
             throw new IllegalStateException("Can only be invoked in the system process");
         }
@@ -221,7 +221,7 @@
 
     /**
      * Retrieves the singleton instance initialized by
-     * {@link #initializeSystemInstance(AndroidPackageProvider)}.
+     * {@link #initializeSystemInstance(PackageProvider)}.
      */
     @NonNull
     public static OverlayConfig getSystemInstance() {
@@ -291,10 +291,10 @@
 
     @NonNull
     private static ArrayList<ParsedOverlayInfo> getOverlayPackageInfos(
-            @NonNull AndroidPackageProvider packageManager) {
+            @NonNull PackageProvider packageManager) {
         final ArrayList<ParsedOverlayInfo> overlays = new ArrayList<>();
-        packageManager.forEachPackage((AndroidPackage p) -> {
-            if (p.getOverlayTarget() != null && p.isSystem()) {
+        packageManager.forEachPackage((ParsingPackageRead p, Boolean isSystem) -> {
+            if (p.getOverlayTarget() != null && isSystem) {
                 overlays.add(new ParsedOverlayInfo(p.getPackageName(), p.getOverlayTarget(),
                         p.getTargetSdkVersion(), p.isOverlayIsStatic(), p.getOverlayPriority(),
                         new File(p.getBaseCodePath())));
diff --git a/core/java/com/android/internal/util/Parcelling.java b/core/java/com/android/internal/util/Parcelling.java
index 390c596..6258a69 100644
--- a/core/java/com/android/internal/util/Parcelling.java
+++ b/core/java/com/android/internal/util/Parcelling.java
@@ -15,10 +15,18 @@
  */
 package com.android.internal.util;
 
+import static java.util.Collections.emptySet;
+
 import android.annotation.Nullable;
 import android.os.Parcel;
+import android.text.TextUtils;
 import android.util.ArrayMap;
+import android.util.ArraySet;
 
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
 import java.util.regex.Pattern;
 
 /**
@@ -90,6 +98,132 @@
      */
     interface BuiltIn {
 
+        class ForInternedString implements Parcelling<String> {
+            @Override
+            public void parcel(@Nullable String item, Parcel dest, int parcelFlags) {
+                dest.writeString(item);
+            }
+
+            @Nullable
+            @Override
+            public String unparcel(Parcel source) {
+                return TextUtils.safeIntern(source.readString());
+            }
+        }
+
+        class ForInternedStringArray implements Parcelling<String[]> {
+            @Override
+            public void parcel(String[] item, Parcel dest, int parcelFlags) {
+                dest.writeStringArray(item);
+            }
+
+            @Nullable
+            @Override
+            public String[] unparcel(Parcel source) {
+                String[] array = source.readStringArray();
+                if (array != null) {
+                    int size = ArrayUtils.size(array);
+                    for (int index = 0; index < size; index++) {
+                        array[index] = TextUtils.safeIntern(array[index]);
+                    }
+                }
+                return array;
+            }
+        }
+
+        class ForInternedStringList implements Parcelling<List<String>> {
+            @Override
+            public void parcel(List<String> item, Parcel dest, int parcelFlags) {
+                dest.writeStringList(item);
+            }
+
+            @Override
+            public List<String> unparcel(Parcel source) {
+                ArrayList<String> list = source.createStringArrayList();
+                if (list != null) {
+                    int size = list.size();
+                    for (int index = 0; index < size; index++) {
+                        list.set(index, list.get(index).intern());
+                    }
+                }
+                return CollectionUtils.emptyIfNull(list);
+            }
+        }
+
+        class ForInternedStringValueMap implements Parcelling<Map<String, String>> {
+            @Override
+            public void parcel(Map<String, String> item, Parcel dest, int parcelFlags) {
+                dest.writeMap(item);
+            }
+
+            @Override
+            public Map<String, String> unparcel(Parcel source) {
+                ArrayMap<String, String> map = new ArrayMap<>();
+                source.readMap(map, String.class.getClassLoader());
+                for (int index = 0; index < map.size(); index++) {
+                    map.setValueAt(index, TextUtils.safeIntern(map.valueAt(index)));
+                }
+                return map;
+            }
+        }
+
+        class ForInternedStringSet implements Parcelling<Set<String>> {
+            @Override
+            public void parcel(Set<String> item, Parcel dest, int parcelFlags) {
+                if (item == null) {
+                    dest.writeInt(-1);
+                } else {
+                    dest.writeInt(item.size());
+                    for (String string : item) {
+                        dest.writeString(string);
+                    }
+                }
+            }
+
+            @Override
+            public Set<String> unparcel(Parcel source) {
+                final int size = source.readInt();
+                if (size < 0) {
+                    return emptySet();
+                }
+                Set<String> set = new ArraySet<>();
+                for (int count = 0; count < size; count++) {
+                    set.add(TextUtils.safeIntern(source.readString()));
+                }
+                return set;
+            }
+        }
+
+        class ForBoolean implements Parcelling<Boolean> {
+            @Override
+            public void parcel(@Nullable Boolean item, Parcel dest, int parcelFlags) {
+                if (item == null) {
+                    // This writes 1 for null to mirror TypedArray.getInteger(booleanResId, 1)
+                    dest.writeInt(1);
+                } else if (!item) {
+                    dest.writeInt(0);
+                } else {
+                    dest.writeInt(-1);
+                }
+            }
+
+            @Nullable
+            @Override
+            public Boolean unparcel(Parcel source) {
+                switch (source.readInt()) {
+                    default:
+                        throw new IllegalStateException("Malformed Parcel reading Boolean: "
+                                + source);
+                    case 1:
+                        return null;
+                    case 0:
+                        return Boolean.FALSE;
+                    case -1:
+                        return Boolean.TRUE;
+                }
+            }
+        }
+
         class ForPattern implements Parcelling<Pattern> {
 
             @Override
diff --git a/core/tests/coretests/src/com/android/internal/content/OverlayConfigIterationRule.java b/core/tests/coretests/src/com/android/internal/content/OverlayConfigIterationRule.java
index 23655a0..fbf75df 100644
--- a/core/tests/coretests/src/com/android/internal/content/OverlayConfigIterationRule.java
+++ b/core/tests/coretests/src/com/android/internal/content/OverlayConfigIterationRule.java
@@ -21,11 +21,11 @@
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.when;
 
-import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.ParsingPackageRead;
 import android.os.Build;
 import android.util.ArrayMap;
 
-import com.android.internal.content.om.OverlayConfig.AndroidPackageProvider;
+import com.android.internal.content.om.OverlayConfig.PackageProvider;
 import com.android.internal.content.om.OverlayScanner;
 import com.android.internal.content.om.OverlayScanner.ParsedOverlayInfo;
 
@@ -39,14 +39,14 @@
 import java.io.File;
 import java.io.IOException;
 import java.util.Map;
-import java.util.function.Consumer;
+import java.util.function.BiConsumer;
 import java.util.function.Supplier;
 
 /**
  * A {@link TestRule} that runs a test case twice. First, the test case runs with a non-null
  * {@link OverlayScanner} as if the zygote process is scanning the overlay packages
  * and parsing configuration files. The test case then runs with a non-null
- * {@link AndroidPackageProvider} as if the system server is parsing configuration files.
+ * {@link PackageProvider} as if the system server is parsing configuration files.
  *
  * This simulates what will happen on device. If an exception would be thrown in the zygote, then
  * the exception should be thrown in the first run of the test case.
@@ -60,7 +60,7 @@
 
     private final ArrayMap<File, ParsedOverlayInfo> mOverlayStubResults = new ArrayMap<>();
     private Supplier<OverlayScanner> mOverlayScanner;
-    private AndroidPackageProvider mAndroidPackageProvider;
+    private PackageProvider mPkgProvider;
     private Iteration mIteration;
 
     /**
@@ -96,9 +96,9 @@
         return mOverlayScanner;
     }
 
-    /** Retrieves the {@link AndroidPackageProvider} for the current run of the test. */
-    AndroidPackageProvider getPackageProvider() {
-        return mAndroidPackageProvider;
+    /** Retrieves the {@link PackageProvider} for the current run of the test. */
+    PackageProvider getPackageProvider() {
+        return mPkgProvider;
     }
 
     /** Retrieves the current iteration of the test. */
@@ -123,7 +123,7 @@
                     }
                     return scanner;
                 };
-                mAndroidPackageProvider = null;
+                mPkgProvider = null;
                 mIteration = Iteration.ZYGOTE;
                 base.evaluate();
 
@@ -131,14 +131,15 @@
                 // the system server is parsing the configuration files and using PackageManager to
                 // retrieving information of overlays.
                 mOverlayScanner = null;
-                mAndroidPackageProvider = Mockito.mock(AndroidPackageProvider.class);
+                mPkgProvider = Mockito.mock(PackageProvider.class);
                 mIteration = Iteration.SYSTEM_SERVER;
                 doAnswer((InvocationOnMock invocation) -> {
                     final Object[] args = invocation.getArguments();
-                    final Consumer<AndroidPackage> f =  (Consumer<AndroidPackage>) args[0];
+                    final BiConsumer<ParsingPackageRead, Boolean> f =
+                            (BiConsumer<ParsingPackageRead, Boolean>) args[0];
                     for (Map.Entry<File, ParsedOverlayInfo> overlay :
                             mOverlayStubResults.entrySet()) {
-                        final AndroidPackage a = Mockito.mock(AndroidPackage.class);
+                        final ParsingPackageRead a = Mockito.mock(ParsingPackageRead.class);
                         final ParsedOverlayInfo info = overlay.getValue();
                         when(a.getPackageName()).thenReturn(info.packageName);
                         when(a.getOverlayTarget()).thenReturn(info.targetPackageName);
@@ -146,12 +147,10 @@
                         when(a.isOverlayIsStatic()).thenReturn(info.isStatic);
                         when(a.getOverlayPriority()).thenReturn(info.priority);
                         when(a.getBaseCodePath()).thenReturn(info.path.getPath());
-                        when(a.isSystem()).thenReturn(
-                                !info.path.getPath().contains("data/overlay"));
-                        f.accept(a);
+                        f.accept(a, !info.path.getPath().contains("data/overlay"));
                     }
                     return null;
-                }).when(mAndroidPackageProvider).forEachPackage(any());
+                }).when(mPkgProvider).forEachPackage(any());
 
                 base.evaluate();
             }
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index 76f6ef6..4ea6370 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -29,8 +29,10 @@
 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 com.android.server.pm.parsing.pkg.AndroidPackage;
+
 import android.content.pm.parsing.ComponentParseUtils;
+import android.content.pm.parsing.ComponentParseUtils.ParsedMainComponent;
 import android.os.Bundle;
 import android.os.PersistableBundle;
 import android.util.ArrayMap;
@@ -763,8 +765,8 @@
             throws IOException;
 
     /** Returns {@code true} if the specified component is enabled and matches the given flags. */
-    public abstract boolean isEnabledAndMatches(
-            @NonNull ComponentParseUtils.ParsedComponent component, int flags, int userId);
+    public abstract boolean isEnabledAndMatches(@NonNull ParsedMainComponent component, int flags,
+            int userId);
 
     /** Returns {@code true} if the given user requires extra badging for icons. */
     public abstract boolean userNeedsBadging(int userId);
diff --git a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
index b9a30bb..72fae77 100644
--- a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
+++ b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
@@ -512,7 +512,7 @@
         try {
             ParsedPackage pkg = parser.parseParsedPackage(installationPath, 0, false);
             int flags = PackageManager.GET_SIGNING_CERTIFICATES | PackageManager.GET_META_DATA;
-            ApkParseUtils.collectCertificates(pkg, false);
+            pkg.setSigningDetails(ApkParseUtils.collectCertificates(pkg, false));
             return PackageInfoUtils.generate(pkg, null, flags, 0, 0, null, new PackageUserState(),
                     UserHandle.getCallingUserId());
         } catch (Exception e) {
diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
index a1250cb..6a582b1 100644
--- a/services/core/java/com/android/server/pm/AppsFilter.java
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -207,14 +207,14 @@
     /** Returns true if the querying package may query for the potential target package */
     private static boolean canQueryViaComponents(AndroidPackage querying,
             AndroidPackage potentialTarget) {
-        if (querying.getQueriesIntents() != null) {
+        if (!querying.getQueriesIntents().isEmpty()) {
             for (Intent intent : querying.getQueriesIntents()) {
                 if (matchesIntentFilters(intent, potentialTarget)) {
                     return true;
                 }
             }
         }
-        if (querying.getQueriesProviders() != null
+        if (!querying.getQueriesProviders().isEmpty()
                 && matchesProviders(querying.getQueriesProviders(), potentialTarget)) {
             return true;
         }
@@ -223,7 +223,7 @@
 
     private static boolean canQueryViaPackage(AndroidPackage querying,
             AndroidPackage potentialTarget) {
-        return querying.getQueriesPackages() != null
+        return !querying.getQueriesPackages().isEmpty()
                 && querying.getQueriesPackages().contains(potentialTarget.getPackageName());
     }
 
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index f6eb76b..d9cb212 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -209,20 +209,16 @@
 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;
 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.ParsedMainComponent;
 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.pm.parsing.ParsingPackageRead;
+import android.content.pm.parsing.ParsingPackageUtils;
 import android.content.res.Resources;
 import android.content.rollback.IRollbackManager;
 import android.database.ContentObserver;
@@ -341,6 +337,13 @@
 import com.android.server.pm.dex.DexoptOptions;
 import com.android.server.pm.dex.PackageDexUsage;
 import com.android.server.pm.dex.ViewCompiler;
+import com.android.server.pm.parsing.PackageInfoUtils;
+import com.android.server.pm.parsing.PackageParser2;
+import com.android.server.pm.parsing.library.PackageBackwardCompatibility;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
+import com.android.server.pm.parsing.pkg.PackageImpl;
+import com.android.server.pm.parsing.pkg.ParsedPackage;
 import com.android.server.pm.permission.BasePermission;
 import com.android.server.pm.permission.PermissionManagerService;
 import com.android.server.pm.permission.PermissionManagerServiceInternal;
@@ -1011,13 +1014,13 @@
 
     private final AppsFilter mAppsFilter;
 
-    class PackageParserCallback implements PackageParser.Callback {
+    class PackageParserCallback extends PackageParser2.Callback {
         @Override public final boolean hasFeature(String feature) {
             return PackageManagerService.this.hasSystemFeature(feature, 0);
         }
     }
 
-    final PackageParser.Callback mPackageParserCallback = new PackageParserCallback();
+    final PackageParser2.Callback mPackageParserCallback = new PackageParserCallback();
 
     // Currently known shared libraries.
     final ArrayMap<String, LongSparseArray<SharedLibraryInfo>> mSharedLibraries = new ArrayMap<>();
@@ -2033,7 +2036,7 @@
                 mInstantAppRegistry.onPackageInstalledLPw(res.pkg, res.newUsers);
             }
 
-            final String packageName = res.pkg.getAppInfoPackageName();
+            final String packageName = res.pkg.getPackageName();
 
             // Determine the set of users who are adding this package for
             // the first time vs. those who are seeing an update.
@@ -2083,7 +2086,7 @@
                 // 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.isSystemApp();
+                boolean isSystem = res.pkg.isSystem();
                 sendPackageAddedForNewUsers(packageName, isSystem || virtualPreload,
                         virtualPreload /*startReceiver*/, appId, firstUserIds, firstInstantUserIds);
 
@@ -2859,12 +2862,8 @@
             final int systemParseFlags = mDefParseFlags | PackageParser.PARSE_IS_SYSTEM_DIR;
             final int systemScanFlags = scanFlags | SCAN_AS_SYSTEM;
 
-            PackageParser packageParser = new PackageParser();
-            packageParser.setSeparateProcesses(mSeparateProcesses);
-            packageParser.setOnlyCoreApps(mOnlyCore);
-            packageParser.setDisplayMetrics(mMetrics);
-            packageParser.setCacheDir(mCacheDir);
-            packageParser.setCallback(mPackageParserCallback);
+            PackageParser2 packageParser = new PackageParser2(mSeparateProcesses, mOnlyCore,
+                    mMetrics, mCacheDir, mPackageParserCallback);
 
             ExecutorService executorService = ParallelPackageParser.makeExecutorService();
             // Collect vendor/product/system_ext overlay packages. (Do this before scanning
@@ -2902,7 +2901,9 @@
 
             // Parse overlay configuration files to set default enable state, mutability, and
             // priority of system overlays.
-            mOverlayConfig = OverlayConfig.initializeSystemInstance(mPmInternal::forEachPackage);
+            mOverlayConfig = OverlayConfig.initializeSystemInstance(
+                    consumer -> mPmInternal.forEachPackage(
+                            pkg -> consumer.accept(pkg, pkg.isSystem())));
 
             // Prune any system packages that no longer exist.
             final List<String> possiblyDeletedUpdatedSystemApps = new ArrayList<>();
@@ -3044,7 +3045,7 @@
                         // special privileges
                         removePackageLI(pkg, true);
                         try {
-                            final File codePath = new File(pkg.getAppInfoCodePath());
+                            final File codePath = new File(pkg.getCodePath());
                             scanPackageTracedLI(codePath, 0, scanFlags, 0, null);
                         } catch (PackageManagerException e) {
                             Slog.e(TAG, "Failed to parse updated, ex-system package: "
@@ -4208,7 +4209,7 @@
                 throw new SecurityException("Package " + packageName + " is currently frozen!");
             }
 
-            if (!userKeyUnlocked && !ps.pkg.isEncryptionAware()) {
+            if (!userKeyUnlocked && !AndroidPackageUtils.isEncryptionAware(ps.pkg)) {
                 throw new SecurityException("Package " + packageName + " is not encryption aware!");
             }
         }
@@ -4574,7 +4575,7 @@
         // reader
         synchronized (mLock) {
             final AndroidPackage p = mPackages.get(packageName);
-            if (p != null && p.isMatch(flags)) {
+            if (p != null && AndroidPackageUtils.isMatchForSystemOnly(p, flags)) {
                 PackageSetting ps = getPackageSettingInternal(p.getPackageName(), callingUid);
                 if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
                     return -1;
@@ -4604,7 +4605,7 @@
         // reader
         synchronized (mLock) {
             final AndroidPackage p = mPackages.get(packageName);
-            if (p != null && p.isMatch(flags)) {
+            if (p != null && AndroidPackageUtils.isMatchForSystemOnly(p, flags)) {
                 PackageSetting ps = getPackageSetting(p.getPackageName());
                 if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
                     return null;
@@ -8563,7 +8564,7 @@
                 return null;
             }
             final ParsedInstrumentation i = mInstrumentation.get(component);
-            return PackageInfoUtils.generateInstrumentationInfo(i, pkg, flags);
+            return PackageInfoUtils.generateInstrumentationInfo(i, pkg, flags, callingUserId);
         }
     }
 
@@ -8576,11 +8577,12 @@
         if (shouldFilterApplicationLocked(ps, callingUid, callingUserId)) {
             return ParceledListSlice.emptyList();
         }
-        return new ParceledListSlice<>(queryInstrumentationInternal(targetPackage, flags));
+        return new ParceledListSlice<>(queryInstrumentationInternal(targetPackage, flags,
+                callingUserId));
     }
 
     private @NonNull List<InstrumentationInfo> queryInstrumentationInternal(String targetPackage,
-            int flags) {
+            int flags, int userId) {
         ArrayList<InstrumentationInfo> finalList = new ArrayList<>();
 
         // reader
@@ -8593,7 +8595,7 @@
                     AndroidPackage pkg = mPackages.get(p.getPackageName());
                     if (pkg != null) {
                         InstrumentationInfo ii = PackageInfoUtils.generateInstrumentationInfo(p,
-                                pkg, flags);
+                                pkg, flags, userId);
                         if (ii != null) {
                             finalList.add(ii);
                         }
@@ -8606,7 +8608,7 @@
     }
 
     private void scanDirTracedLI(File scanDir, final int parseFlags, int scanFlags,
-            long currentTime, PackageParser packageParser, ExecutorService executorService) {
+            long currentTime, PackageParser2 packageParser, ExecutorService executorService) {
         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanDir [" + scanDir.getAbsolutePath() + "]");
         try {
             scanDirLI(scanDir, parseFlags, scanFlags, currentTime, packageParser, executorService);
@@ -8616,7 +8618,7 @@
     }
 
     private void scanDirLI(File scanDir, int parseFlags, int scanFlags, long currentTime,
-            PackageParser packageParser, ExecutorService executorService) {
+            PackageParser2 packageParser, ExecutorService executorService) {
         final File[] files = scanDir.listFiles();
         if (ArrayUtils.isEmpty(files)) {
             Log.d(TAG, "No files in app dir " + scanDir);
@@ -8720,7 +8722,8 @@
 
         try {
             Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates");
-            ApkParseUtils.collectCertificates(parsedPackage, skipVerify);
+            parsedPackage.setSigningDetails(
+                    ParsingPackageUtils.collectCertificates(parsedPackage, skipVerify));
         } catch (PackageParserException e) {
             throw PackageManagerException.from(e);
         } finally {
@@ -8774,16 +8777,13 @@
     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();
-        pp.setSeparateProcesses(mSeparateProcesses);
-        pp.setOnlyCoreApps(mOnlyCore);
-        pp.setDisplayMetrics(mMetrics);
-        pp.setCallback(mPackageParserCallback);
+        PackageParser2 pp = new PackageParser2(mSeparateProcesses, mOnlyCore, mMetrics, null,
+                mPackageParserCallback);
 
         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");
         final ParsedPackage parsedPackage;
         try {
-            parsedPackage = pp.parseParsedPackage(scanFile, parseFlags, false);
+            parsedPackage = pp.parsePackage(scanFile, parseFlags, false);
         } catch (PackageParserException e) {
             throw PackageManagerException.from(e);
         } finally {
@@ -8869,18 +8869,6 @@
         final boolean pkgAlreadyExists;
         PackageSetting pkgSetting;
 
-        // NOTE: installPackageLI() has the same code to setup the package's
-        // application info. This probably should be done lower in the call
-        // stack [such as scanPackageOnly()]. However, we verify the application
-        // info prior to that [in scanPackageNew()] and thus have to setup
-        // the application info early.
-        // 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(parsedPackage.getRealPackage());
             final String realPkgName = getRealPackageName(parsedPackage, renamedPkgName);
@@ -9957,7 +9945,7 @@
         // Or:
         // - 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 (AndroidPackageUtils.isLibrary(pkg)) {
             if (pkg.getStaticSharedLibName() != null) {
                 SharedLibraryInfo definedLibrary = getSharedLibraryInfoLPr(
                         pkg.getStaticSharedLibName(), pkg.getStaticSharedLibVersion());
@@ -9994,7 +9982,7 @@
             }
         }
         if (p != null) {
-            usesLibraryFiles.addAll(p.getAllCodePaths());
+            usesLibraryFiles.addAll(AndroidPackageUtils.getAllCodePaths(p));
             // If the package provides libraries, add the dependency to them.
             applyDefiningSharedLibraryUpdateLocked(pkg, libInfo, (definingLibrary, dependency) -> {
                 definingLibrary.addDependency(dependency);
@@ -10026,18 +10014,18 @@
         // that libraries are searched in the correct order) and must have no
         // duplicates.
         ArrayList<SharedLibraryInfo> usesLibraryInfos = null;
-        if (pkg.getUsesLibraries() != null) {
+        if (!pkg.getUsesLibraries().isEmpty()) {
             usesLibraryInfos = collectSharedLibraryInfos(pkg.getUsesLibraries(), null, null,
                     pkg.getPackageName(), true, pkg.getTargetSdkVersion(), null,
                     availablePackages, existingLibraries, newLibraries);
         }
-        if (pkg.getUsesStaticLibraries() != null) {
+        if (!pkg.getUsesStaticLibraries().isEmpty()) {
             usesLibraryInfos = collectSharedLibraryInfos(pkg.getUsesStaticLibraries(),
                     pkg.getUsesStaticLibrariesVersions(), pkg.getUsesStaticLibrariesCertDigests(),
                     pkg.getPackageName(), true, pkg.getTargetSdkVersion(), usesLibraryInfos,
                     availablePackages, existingLibraries, newLibraries);
         }
-        if (pkg.getUsesOptionalLibraries() != null) {
+        if (!pkg.getUsesOptionalLibraries().isEmpty()) {
             usesLibraryInfos = collectSharedLibraryInfos(pkg.getUsesOptionalLibraries(),
                     null, null, pkg.getPackageName(), false, pkg.getTargetSdkVersion(),
                     usesLibraryInfos, availablePackages, existingLibraries, newLibraries);
@@ -10607,7 +10595,7 @@
         }
         pkgSetting.signatures.mSigningDetails = reconciledPkg.signingDetails;
 
-        if (pkg.getAdoptPermissions() != null) {
+        if (!pkg.getAdoptPermissions().isEmpty()) {
             // This package wants to adopt ownership of permissions from
             // another package.
             for (int i = pkg.getAdoptPermissions().size() - 1; i >= 0; i--) {
@@ -10848,8 +10836,8 @@
         }
 
         // Initialize package source and resource directories
-        final File destCodeFile = new File(parsedPackage.getAppInfoCodePath());
-        final File destResourceFile = new File(parsedPackage.getAppInfoResourcePath());
+        final File destCodeFile = new File(parsedPackage.getCodePath());
+        final File destResourceFile = new File(parsedPackage.getCodePath());
 
         // 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.
@@ -10878,7 +10866,7 @@
         }
 
         String[] usesStaticLibraries = null;
-        if (parsedPackage.getUsesStaticLibraries() != null) {
+        if (!parsedPackage.getUsesStaticLibraries().isEmpty()) {
             usesStaticLibraries = new String[parsedPackage.getUsesStaticLibraries().size()];
             parsedPackage.getUsesStaticLibraries().toArray(usesStaticLibraries);
         }
@@ -10898,8 +10886,7 @@
         } else {
             // make a deep copy to avoid modifying any existing system state.
             pkgSetting = new PackageSetting(pkgSetting);
-            // TODO(b/135203078): Remove entirely. Set package directly.
-            parsedPackage.setPackageSettingCallback(pkgSetting);
+            pkgSetting.pkg = parsedPackage;
 
             // REMOVE SharedUserSetting from method; update in a separate call.
             //
@@ -10945,9 +10932,7 @@
                 .setSeInfo(SELinuxMMAC.getSeInfo(parsedPackage, sharedUserSetting,
                         injector.getCompatibility()))
                 .setSeInfoUser(SELinuxUtil.assignSeinfoUser(pkgSetting.readUserState(
-                        userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : userId)))
-                .setProcessName(fixProcessName(parsedPackage.getPackageName(),
-                        parsedPackage.getProcessName()));
+                        userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : userId)));
 
         if (!isPlatformPackage) {
             // Get all of our default paths setup
@@ -10964,7 +10949,7 @@
         if ((scanFlags & SCAN_NEW_INSTALL) == 0) {
             if (needToDeriveAbi) {
                 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "derivePackageAbi");
-                final boolean extractNativeLibs = !parsedPackage.isLibrary();
+                final boolean extractNativeLibs = !AndroidPackageUtils.isLibrary(parsedPackage);
                 final Pair<PackageAbiHelper.Abis, PackageAbiHelper.NativeLibraryPaths> derivedAbi =
                         packageAbiHelper.derivePackageAbi(parsedPackage, cpuAbiOverride,
                                 extractNativeLibs);
@@ -11104,13 +11089,13 @@
         }
         pkgSetting.setTimeStamp(scanFileTime);
         // TODO(b/135203078): Remove, move to constructor
-        parsedPackage.setPackageSettingCallback(pkgSetting);
+        pkgSetting.pkg = parsedPackage;
         pkgSetting.pkgFlags = parsedPackage.getFlags();
         if (parsedPackage.getLongVersionCode() != pkgSetting.versionCode) {
             pkgSetting.versionCode = parsedPackage.getLongVersionCode();
         }
         // Update volume if needed
-        final String volumeUuid = parsedPackage.getApplicationInfoVolumeUuid();
+        final String volumeUuid = parsedPackage.getVolumeUuid();
         if (!Objects.equals(volumeUuid, pkgSetting.volumeUuid)) {
             Slog.i(PackageManagerService.TAG,
                     "Update" + (pkgSetting.isSystem() ? " system" : "")
@@ -11122,14 +11107,15 @@
 
         SharedLibraryInfo staticSharedLibraryInfo = null;
         if (!TextUtils.isEmpty(parsedPackage.getStaticSharedLibName())) {
-            staticSharedLibraryInfo = SharedLibraryInfo.createForStatic(parsedPackage);
+            staticSharedLibraryInfo =
+                    AndroidPackageUtils.createSharedLibraryForStatic(parsedPackage);
         }
         List<SharedLibraryInfo> dynamicSharedLibraryInfos = null;
         if (!ArrayUtils.isEmpty(parsedPackage.getLibraryNames())) {
             dynamicSharedLibraryInfos = new ArrayList<>(parsedPackage.getLibraryNames().size());
             for (String name : parsedPackage.getLibraryNames()) {
                 dynamicSharedLibraryInfos.add(
-                        SharedLibraryInfo.createForDynamic(parsedPackage, name));
+                        AndroidPackageUtils.createSharedLibraryForDynamic(parsedPackage, name));
             }
         }
 
@@ -11202,7 +11188,7 @@
                 parsedPackage.setAllComponentsDirectBootAware(true);
             }
             if (compressedFileExists(parsedPackage.getCodePath())) {
-                parsedPackage.setIsStub(true);
+                parsedPackage.setStub(true);
             }
         } else {
             parsedPackage
@@ -11257,7 +11243,7 @@
 
     private <T extends ComponentParseUtils.ParsedMainComponent>
             void assertPackageProcesses(AndroidPackage pkg, List<T> components,
-            ArrayMap<String, ComponentParseUtils.ParsedProcess> procs, String compName)
+            Map<String, ComponentParseUtils.ParsedProcess> procs, String compName)
             throws PackageManagerException {
         if (components == null) {
             return;
@@ -11291,8 +11277,7 @@
             assertCodePolicy(pkg);
         }
 
-        if (pkg.getAppInfoCodePath() == null ||
-                pkg.getAppInfoResourcePath() == null) {
+        if (pkg.getCodePath() == 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");
@@ -11375,49 +11360,49 @@
                 }
 
                 // Static shared libs cannot declare activities
-                if (pkg.getActivities() != null && !pkg.getActivities().isEmpty()) {
+                if (!pkg.getActivities().isEmpty()) {
                     throw new PackageManagerException(
                             "Static shared libs cannot declare activities");
                 }
 
                 // Static shared libs cannot declare services
-                if (pkg.getServices() != null && !pkg.getServices().isEmpty()) {
+                if (!pkg.getServices().isEmpty()) {
                     throw new PackageManagerException(
                             "Static shared libs cannot declare services");
                 }
 
                 // Static shared libs cannot declare providers
-                if (pkg.getProviders() != null && !pkg.getProviders().isEmpty()) {
+                if (!pkg.getProviders().isEmpty()) {
                     throw new PackageManagerException(
                             "Static shared libs cannot declare content providers");
                 }
 
                 // Static shared libs cannot declare receivers
-                if (pkg.getReceivers() != null && !pkg.getReceivers().isEmpty()) {
+                if (!pkg.getReceivers().isEmpty()) {
                     throw new PackageManagerException(
                             "Static shared libs cannot declare broadcast receivers");
                 }
 
                 // Static shared libs cannot declare permission groups
-                if (pkg.getPermissionGroups() != null && !pkg.getPermissionGroups().isEmpty()) {
+                if (!pkg.getPermissionGroups().isEmpty()) {
                     throw new PackageManagerException(
                             "Static shared libs cannot declare permission groups");
                 }
 
                 // Static shared libs cannot declare features
-                if (pkg.getFeatures() != null && !pkg.getFeatures().isEmpty()) {
+                if (!pkg.getFeatures().isEmpty()) {
                     throw new PackageManagerException(
                             "Static shared libs cannot declare features");
                 }
 
                 // Static shared libs cannot declare permissions
-                if (pkg.getPermissions() != null && !pkg.getPermissions().isEmpty()) {
+                if (!pkg.getPermissions().isEmpty()) {
                     throw new PackageManagerException(
                             "Static shared libs cannot declare permissions");
                 }
 
                 // Static shared libs cannot declare protected broadcasts
-                if (pkg.getProtectedBroadcasts() != null) {
+                if (!pkg.getProtectedBroadcasts().isEmpty()) {
                     throw new PackageManagerException(
                             "Static shared libs cannot declare protected broadcasts");
                 }
@@ -11479,12 +11464,11 @@
                                     + " and requiring known paths " + known.codePathString
                                     + " & " + known.resourcePathString);
                         }
-                        if (!pkg.getAppInfoCodePath().equals(known.codePathString)
-                                || !pkg.getAppInfoResourcePath().equals(
-                                        known.resourcePathString)) {
+                        if (!pkg.getCodePath().equals(known.codePathString)
+                                || !pkg.getCodePath().equals(known.resourcePathString)) {
                             throw new PackageManagerException(INSTALL_FAILED_PACKAGE_CHANGED,
                                     "Application package " + pkg.getPackageName()
-                                    + " found at " + pkg.getAppInfoCodePath()
+                                    + " found at " + pkg.getCodePath()
                                     + " but expected at " + known.codePathString
                                     + "; ignoring.");
                         }
@@ -11506,8 +11490,8 @@
 
             // If this package has defined explicit processes, then ensure that these are
             // the only processes used by its components.
-            final ArrayMap<String, ComponentParseUtils.ParsedProcess> procs = pkg.getProcesses();
-            if (procs != null) {
+            final Map<String, ComponentParseUtils.ParsedProcess> procs = pkg.getProcesses();
+            if (!procs.isEmpty()) {
                 if (!procs.containsKey(pkg.getProcessName())) {
                     throw new PackageManagerException(
                             INSTALL_FAILED_PROCESS_NOT_DEFINED,
@@ -11793,7 +11777,7 @@
         if (clientLibPkgs != null) {
             for (int i=0; i<clientLibPkgs.size(); i++) {
                 AndroidPackage clientPkg = clientLibPkgs.get(i);
-                killApplication(clientPkg.getAppInfoPackageName(),
+                killApplication(clientPkg.getPackageName(),
                         clientPkg.getUid(), "update lib");
             }
         }
@@ -11807,7 +11791,7 @@
             // Add the new setting to mSettings
             mSettings.insertPackageSettingLPw(pkgSetting, pkg);
             // Add the new setting to mPackages
-            mPackages.put(pkg.getAppInfoPackageName(), pkg);
+            mPackages.put(pkg.getPackageName(), pkg);
             if ((scanFlags & SCAN_AS_APK_IN_APEX) != 0) {
                 mApexManager.registerApkInApex(pkg);
             }
@@ -11887,8 +11871,8 @@
             // Set up information for custom user intent resolution activity.
             mResolveActivity.applicationInfo = pkg.toAppInfoWithoutState();
             mResolveActivity.name = mCustomResolverComponentName.getClassName();
-            mResolveActivity.packageName = pkg.getAppInfoPackageName();
-            mResolveActivity.processName = pkg.getAppInfoProcessName();
+            mResolveActivity.packageName = pkg.getPackageName();
+            mResolveActivity.processName = pkg.getProcessName();
             mResolveActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
             mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS |
                     ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS;
@@ -13727,7 +13711,7 @@
             try {
                 if (bm.isUserReadyForBackup(userId)) {
                     bm.restoreAtInstallForUser(
-                            userId, res.pkg.getAppInfoPackageName(), token);
+                            userId, res.pkg.getPackageName(), token);
                 } else {
                     Slog.w(TAG, "User " + userId + " is not ready. Restore at install "
                             + "didn't take place.");
@@ -13755,7 +13739,7 @@
         IRollbackManager rm = IRollbackManager.Stub.asInterface(
                 ServiceManager.getService(Context.ROLLBACK_SERVICE));
 
-        final String packageName = res.pkg.getAppInfoPackageName();
+        final String packageName = res.pkg.getPackageName();
         final String seInfo = res.pkg.getSeInfo();
         final int[] allUsers = mUserManager.getUserIds();
         final int[] installedUsers;
@@ -13815,7 +13799,7 @@
                 if (data.res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
                     continue;
                 }
-                if (packageName.equals(data.res.pkg.getAppInfoPackageName())) {
+                if (packageName.equals(data.res.pkg.getPackageName())) {
                     // 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]) {
@@ -15000,14 +14984,6 @@
             parsedPackage.setSplitCodePaths(FileUtils.rewriteAfterRename(beforeCodeFile,
                     afterCodeFile, parsedPackage.getSplitCodePaths()));
 
-            // Reflect the rename in app info
-            // 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;
         }
 
@@ -15117,14 +15093,6 @@
                 return false;
             }
 
-            // Reflect the move in app info
-            // 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;
         }
 
@@ -15922,8 +15890,8 @@
                         // 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.getAppInfoCodePath(),
-                                oldPackage.getAppInfoResourcePath(),
+                                oldPackage.getCodePath(),
+                                oldPackage.getCodePath(),
                                 getAppDexInstructionSets(oldPackage.getPrimaryCpuAbi(),
                                         oldPackage.getSecondaryCpuAbi()));
                     } else {
@@ -15944,14 +15912,14 @@
 
                     // If deleted package lived in a container, give users a chance to
                     // relinquish resources before killing.
-                    if (oldPackage.isForwardLocked() || isExternal(oldPackage)) {
+                    if (isExternal(oldPackage)) {
                         if (DEBUG_INSTALL) {
                             Slog.i(TAG, "upgrading pkg " + oldPackage
                                     + " is ASEC-hosted -> UNAVAILABLE");
                         }
                         final int[] uidArray = new int[]{oldPackage.getUid()};
                         final ArrayList<String> pkgList = new ArrayList<>(1);
-                        pkgList.add(oldPackage.getAppInfoPackageName());
+                        pkgList.add(oldPackage.getPackageName());
                         sendResourcesChangedBroadcast(false, true, pkgList, uidArray, null);
                     }
 
@@ -16328,16 +16296,14 @@
                 | PackageParser.PARSE_ENFORCE_CODE
                 | (onExternal ? PackageParser.PARSE_EXTERNAL_STORAGE : 0);
 
-        PackageParser pp = new PackageParser();
-        pp.setSeparateProcesses(mSeparateProcesses);
-        pp.setDisplayMetrics(mMetrics);
-        pp.setCallback(mPackageParserCallback);
+        PackageParser2 pp = new PackageParser2(mSeparateProcesses, false, mMetrics, null,
+                mPackageParserCallback);
 
         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");
         ParsedPackage parsedPackage;
         try {
-            parsedPackage = pp.parseParsedPackage(tmpPackageFile, parseFlags, false);
-            DexMetadataHelper.validatePackageDexMetadata(parsedPackage);
+            parsedPackage = pp.parsePackage(tmpPackageFile, parseFlags, false);
+            AndroidPackageUtils.validatePackageDexMetadata(parsedPackage);
         } catch (PackageParserException e) {
             throw new PrepareFailure("Failed parse during installPackageLI", e);
         } finally {
@@ -16393,7 +16359,8 @@
                 parsedPackage.setSigningDetails(args.signingDetails);
             } else {
                 // TODO(b/136132412): skip for Incremental installation
-                ApkParseUtils.collectCertificates(parsedPackage, false /* skipVerify */);
+                parsedPackage.setSigningDetails(
+                        ParsingPackageUtils.collectCertificates(parsedPackage, false /* skipVerify */));
             }
         } catch (PackageParserException e) {
             throw new PrepareFailure("Failed collect during installPackageLI", e);
@@ -16636,7 +16603,7 @@
             try {
                 String abiOverride = (TextUtils.isEmpty(parsedPackage.getCpuAbiOverride())
                         ? args.abiOverride : parsedPackage.getCpuAbiOverride());
-                final boolean extractNativeLibs = !parsedPackage.isLibrary();
+                final boolean extractNativeLibs = !AndroidPackageUtils.isLibrary(parsedPackage);
                 final Pair<PackageAbiHelper.Abis, PackageAbiHelper.NativeLibraryPaths>
                         derivedAbi = mInjector.getAbiHelper().derivePackageAbi(
                                 parsedPackage, abiOverride, extractNativeLibs);
@@ -19980,7 +19947,7 @@
                 // We're dealing with a component level state change
                 // First, verify that this is a valid class name.
                 AndroidPackage pkg = pkgSetting.pkg;
-                if (pkg == null || !pkg.hasComponentClassName(className)) {
+                if (pkg == null || !AndroidPackageUtils.hasComponentClassName(pkg, className)) {
                     if (pkg != null &&
                             pkg.getTargetSdkVersion() >=
                                     Build.VERSION_CODES.JELLY_BEAN) {
@@ -21336,7 +21303,7 @@
         final int[] packageUids = new int[size];
         for (int i = 0; i < size; i++) {
             final AndroidPackage pkg = packages.get(i);
-            packageNames[i] = pkg.getAppInfoPackageName();
+            packageNames[i] = pkg.getPackageName();
             packageUids[i] = pkg.getUid();
         }
         sendResourcesChangedBroadcast(mediaStatus, replacing, packageNames, packageUids,
@@ -21801,7 +21768,7 @@
             ceDataInode = mInstaller.createAppData(volumeUuid, packageName, userId, flags,
                     appId, seInfo, pkg.getTargetSdkVersion());
         } catch (InstallerException e) {
-            if (pkg.isSystemApp()) {
+            if (pkg.isSystem()) {
                 logCriticalInfo(Log.ERROR, "Failed to create app data for " + packageName
                         + ", but trying to recover: " + e);
                 destroyAppDataLeafLIF(pkg, userId, flags);
@@ -22054,7 +22021,7 @@
                     || shouldFilterApplicationLocked(ps, callingUid, user.getIdentifier())) {
                 throw new PackageManagerException(MOVE_FAILED_DOESNT_EXIST, "Missing package");
             }
-            if (pkg.isSystemApp()) {
+            if (pkg.isSystem()) {
                 throw new PackageManagerException(MOVE_FAILED_SYSTEM_PACKAGE,
                         "Cannot move system application");
             }
@@ -22080,7 +22047,7 @@
                 throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR,
                         "Package already moved to " + volumeUuid);
             }
-            if (pkg.isInternal() && isPackageDeviceAdminOnAnyUser(packageName)) {
+            if (!pkg.isExternalStorage() && isPackageDeviceAdminOnAnyUser(packageName)) {
                 throw new PackageManagerException(MOVE_FAILED_DEVICE_ADMIN,
                         "Device admin cannot be moved");
             }
@@ -23352,7 +23319,7 @@
         }
 
         @Override
-        public boolean isEnabledAndMatches(ParsedComponent component, int flags, int userId) {
+        public boolean isEnabledAndMatches(ParsedMainComponent component, int flags, int userId) {
             synchronized (mLock) {
                 AndroidPackage pkg = getPackage(component.getPackageName());
                 return mSettings.isEnabledAndMatchLPr(pkg, component, flags, userId);
@@ -24177,12 +24144,12 @@
             if (p == null) {
                 return false;
             }
-            return p.canHaveOatDir();
+            return AndroidPackageUtils.canHaveOatDir(p, p.isUpdatedSystemApp());
         }
     }
 
     private String getOatDir(AndroidPackage pkg) {
-        if (!pkg.canHaveOatDir()) {
+        if (!AndroidPackageUtils.canHaveOatDir(pkg, pkg.isUpdatedSystemApp())) {
             return null;
         }
         File codePath = new File(pkg.getCodePath());
@@ -24202,7 +24169,7 @@
         }
         instructionSets = getAppDexInstructionSets(pkg.getPrimaryCpuAbi(),
                 pkg.getSecondaryCpuAbi());
-        codePaths = pkg.getAllCodePaths();
+        codePaths = AndroidPackageUtils.getAllCodePaths(pkg);
         oatDir = getOatDir(pkg);
 
         for (String codePath : codePaths) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index a9035b2..6040224 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -40,8 +40,7 @@
 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.content.pm.parsing.ParsingPackageUtils;
 import android.os.Build;
 import android.os.Debug;
 import android.os.Environment;
@@ -66,6 +65,7 @@
 import com.android.server.EventLogTags;
 import com.android.server.pm.dex.DexManager;
 import com.android.server.pm.dex.PackageDexUsage;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.permission.PermissionsState;
 
 import dalvik.system.VMRuntime;
@@ -544,7 +544,8 @@
     private static boolean matchSignatureInSystem(PackageSetting pkgSetting,
             PackageSetting disabledPkgSetting) {
         try {
-            ApkParseUtils.collectCertificates(disabledPkgSetting.pkg, true /* skipVerify */);
+            disabledPkgSetting.pkg.mutate().setSigningDetails(
+                    ParsingPackageUtils.collectCertificates(disabledPkgSetting.pkg, true /* skipVerify */));
             if (pkgSetting.signatures.mSigningDetails.checkCapability(
                     disabledPkgSetting.signatures.mSigningDetails,
                     PackageParser.SigningDetails.CertCapabilities.INSTALLED_DATA)
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index d83e6f4..97342c0 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -20,13 +20,12 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 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.ArrayMap;
 import android.util.ArraySet;
 import android.util.proto.ProtoOutputStream;
 
+import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.permission.PermissionsState;
 
 import java.io.File;
@@ -39,8 +38,7 @@
 /**
  * Settings data for a particular package we know about.
  */
-public final class PackageSetting extends PackageSettingBase implements
-        ParsedPackage.PackageSettingCallback {
+public final class PackageSetting extends PackageSettingBase {
     int appId;
 
     public AndroidPackage pkg;
@@ -323,10 +321,4 @@
         Set<String> mimeGroupNames = other.mimeGroups != null ? other.mimeGroups.keySet() : null;
         updateMimeGroups(mimeGroupNames);
     }
-
-    // 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/ParallelPackageParser.java b/services/core/java/com/android/server/pm/ParallelPackageParser.java
index 448dad0..21334c0 100644
--- a/services/core/java/com/android/server/pm/ParallelPackageParser.java
+++ b/services/core/java/com/android/server/pm/ParallelPackageParser.java
@@ -19,12 +19,13 @@
 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 com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ConcurrentUtils;
+import com.android.server.pm.parsing.PackageParser2;
+import com.android.server.pm.parsing.pkg.ParsedPackage;
 
 import java.io.File;
 import java.util.concurrent.ArrayBlockingQueue;
@@ -50,11 +51,11 @@
                 Process.THREAD_PRIORITY_FOREGROUND);
     }
 
-    private final PackageParser mPackageParser;
+    private final PackageParser2 mPackageParser;
 
     private final ExecutorService mExecutorService;
 
-    ParallelPackageParser(PackageParser packageParser, ExecutorService executorService) {
+    ParallelPackageParser(PackageParser2 packageParser, ExecutorService executorService) {
         mPackageParser = packageParser;
         mExecutorService = executorService;
     }
@@ -125,6 +126,6 @@
     @VisibleForTesting
     protected ParsedPackage parsePackage(File scanFile, int parseFlags)
             throws PackageParser.PackageParserException {
-        return mPackageParser.parseParsedPackage(scanFile, parseFlags, true);
+        return mPackageParser.parsePackage(scanFile, parseFlags, true);
     }
 }
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 60c8b94..5694428 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -3155,7 +3155,7 @@
                 LocalServices.getService(PackageManagerInternal.class);
         for (PackageSetting ps : mPackages.values()) {
             if ((ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0 && ps.pkg != null
-                    && ps.pkg.getPreferredActivityFilters() != null) {
+                    && !ps.pkg.getPreferredActivityFilters().isEmpty()) {
                 List<ComponentParseUtils.ParsedActivityIntentInfo> intents
                         = ps.pkg.getPreferredActivityFilters();
                 for (int i=0; i<intents.size(); i++) {
@@ -4608,10 +4608,10 @@
                 pw.print(" (override=true)");
             }
             pw.println();
-            if (ps.pkg.getQueriesPackages() != null) {
+            if (ps.pkg.getQueriesPackages().isEmpty()) {
                 pw.append(prefix).append("  queriesPackages=").println(ps.pkg.getQueriesPackages());
             }
-            if (ps.pkg.getQueriesIntents() != null) {
+            if (!ps.pkg.getQueriesIntents().isEmpty()) {
                 pw.append(prefix).append("  queriesIntents=").println(ps.pkg.getQueriesIntents());
             }
             pw.print(prefix); pw.print("  dataDir="); pw.println(ps.pkg.getDataDir());
@@ -4707,11 +4707,10 @@
                     pw.print(prefix); pw.print("    "); pw.println(usesLibraryFiles[i]);
                 }
             }
-            final ArrayMap<String, ComponentParseUtils.ParsedProcess> procs = pkg.getProcesses();
-            if (procs != null) {
+            final Map<String, ComponentParseUtils.ParsedProcess> procs = pkg.getProcesses();
+            if (!procs.isEmpty()) {
                 pw.print(prefix); pw.println("  processes:");
-                for (int i = 0; i < procs.size(); i++) {
-                    final ComponentParseUtils.ParsedProcess proc = procs.valueAt(i);
+                for (ComponentParseUtils.ParsedProcess proc : procs.values()) {
                     pw.print(prefix); pw.print("    "); pw.println(proc.name);
                     if (proc.deniedPermissions != null) {
                         for (int j = 0; j < proc.deniedPermissions.size(); j++) {
@@ -4751,7 +4750,7 @@
             pw.print(prefix); pw.print("  overlayCategory="); pw.println(pkg.getOverlayCategory());
         }
 
-        if (pkg != null && pkg.getPermissions() != null && pkg.getPermissions().size() > 0) {
+        if (pkg != null && !pkg.getPermissions().isEmpty()) {
             final List<ParsedPermission> perms = pkg.getPermissions();
             pw.print(prefix); pw.println("  declared permissions:");
             for (int i=0; i<perms.size(); i++) {
diff --git a/services/core/java/com/android/server/pm/parsing/PackageCacher.java b/services/core/java/com/android/server/pm/parsing/PackageCacher.java
new file mode 100644
index 0000000..e5e1b0b
--- /dev/null
+++ b/services/core/java/com/android/server/pm/parsing/PackageCacher.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2020 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.parsing;
+
+import android.annotation.NonNull;
+import android.content.pm.PackageParserCacheHelper;
+import android.os.Parcel;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.OsConstants;
+import android.system.StructStat;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.pm.parsing.pkg.PackageImpl;
+import com.android.server.pm.parsing.pkg.ParsedPackage;
+
+import libcore.io.IoUtils;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class PackageCacher {
+
+    private static final String TAG = "PackageCacher";
+
+    /**
+     * Total number of packages that were read from the cache.  We use it only for logging.
+     */
+    public static final AtomicInteger sCachedPackageReadCount = new AtomicInteger();
+
+    @NonNull
+    private File mCacheDir;
+
+    public PackageCacher(@NonNull File cacheDir) {
+        this.mCacheDir = cacheDir;
+    }
+
+    /**
+     * 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());
+        sb.append('-');
+        sb.append(flags);
+
+        return sb.toString();
+    }
+
+    @VisibleForTesting
+    protected ParsedPackage fromCacheEntry(byte[] bytes) {
+        return fromCacheEntryStatic(bytes);
+    }
+
+    /** static version of {@link #fromCacheEntry} for unit tests. */
+    @VisibleForTesting
+    public static ParsedPackage fromCacheEntryStatic(byte[] bytes) {
+        final Parcel p = Parcel.obtain();
+        p.unmarshall(bytes, 0, bytes.length);
+        p.setDataPosition(0);
+
+        final PackageParserCacheHelper.ReadHelper helper = new PackageParserCacheHelper.ReadHelper(p);
+        helper.startAndInstall();
+
+        // TODO(b/135203078): Hide PackageImpl constructor?
+        ParsedPackage pkg = new PackageImpl(p);
+
+        p.recycle();
+
+        sCachedPackageReadCount.incrementAndGet();
+
+        return pkg;
+    }
+
+    @VisibleForTesting
+    protected byte[] toCacheEntry(ParsedPackage pkg) {
+        return toCacheEntryStatic(pkg);
+
+    }
+
+    /** static version of {@link #toCacheEntry} for unit tests. */
+    @VisibleForTesting
+    public static byte[] toCacheEntryStatic(ParsedPackage pkg) {
+        final Parcel p = Parcel.obtain();
+        final PackageParserCacheHelper.WriteHelper helper = new PackageParserCacheHelper.WriteHelper(p);
+
+        pkg.writeToParcel(p, 0 /* flags */);
+
+        helper.finishAndUninstall();
+
+        byte[] serialized = p.marshall();
+        p.recycle();
+
+        return serialized;
+    }
+
+    /**
+     * Given a {@code packageFile} and a {@code cacheFile} returns whether the
+     * cache file is up to date based on the mod-time of both files.
+     */
+    private static boolean isCacheUpToDate(File packageFile, File cacheFile) {
+        try {
+            // NOTE: We don't use the File.lastModified API because it has the very
+            // non-ideal failure mode of returning 0 with no excepions thrown.
+            // The nio2 Files API is a little better but is considerably more expensive.
+            final StructStat pkg = Os.stat(packageFile.getAbsolutePath());
+            final StructStat cache = Os.stat(cacheFile.getAbsolutePath());
+            return pkg.st_mtime < cache.st_mtime;
+        } catch (ErrnoException ee) {
+            // The most common reason why stat fails is that a given cache file doesn't
+            // exist. We ignore that here. It's easy to reason that it's safe to say the
+            // cache isn't up to date if we see any sort of exception here.
+            //
+            // (1) Exception while stating the package file : This should never happen,
+            // and if it does, we do a full package parse (which is likely to throw the
+            // same exception).
+            // (2) Exception while stating the cache file : If the file doesn't exist, the
+            // cache is obviously out of date. If the file *does* exist, we can't read it.
+            // We will attempt to delete and recreate it after parsing the package.
+            if (ee.errno != OsConstants.ENOENT) {
+                Slog.w("Error while stating package cache : ", ee);
+            }
+
+            return false;
+        }
+    }
+
+    /**
+     * Returns the cached parse result for {@code packageFile} for parse flags {@code flags},
+     * or {@code null} if no cached result exists.
+     */
+    public ParsedPackage getCachedResult(File packageFile, int flags) {
+        final String cacheKey = getCacheKey(packageFile, flags);
+        final File cacheFile = new File(mCacheDir, cacheKey);
+
+        try {
+            // If the cache is not up to date, return null.
+            if (!isCacheUpToDate(packageFile, cacheFile)) {
+                return null;
+            }
+
+            final byte[] bytes = IoUtils.readFileAsByteArray(cacheFile.getAbsolutePath());
+            return fromCacheEntry(bytes);
+        } catch (Throwable e) {
+            Slog.w(TAG, "Error reading package cache: ", e);
+
+            // If something went wrong while reading the cache entry, delete the cache file
+            // so that we regenerate it the next time.
+            cacheFile.delete();
+            return null;
+        }
+    }
+
+    /**
+     * Caches the parse result for {@code packageFile} with flags {@code flags}.
+     */
+    public void cacheResult(File packageFile, int flags, ParsedPackage parsed) {
+        try {
+            final String cacheKey = getCacheKey(packageFile, flags);
+            final File cacheFile = new File(mCacheDir, cacheKey);
+
+            if (cacheFile.exists()) {
+                if (!cacheFile.delete()) {
+                    Slog.e(TAG, "Unable to delete cache file: " + cacheFile);
+                }
+            }
+
+            final byte[] cacheEntry = toCacheEntry(parsed);
+
+            if (cacheEntry == null) {
+                return;
+            }
+
+            try (FileOutputStream fos = new FileOutputStream(cacheFile)) {
+                fos.write(cacheEntry);
+            } catch (IOException ioe) {
+                Slog.w(TAG, "Error writing cache entry.", ioe);
+                cacheFile.delete();
+            }
+        } catch (Throwable e) {
+            Slog.w(TAG, "Error saving package cache.", e);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
new file mode 100644
index 0000000..3d56962
--- /dev/null
+++ b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
@@ -0,0 +1,419 @@
+/*
+ * Copyright (C) 2020 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.parsing;
+
+import android.annotation.CheckResult;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.apex.ApexInfo;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.ComponentInfo;
+import android.content.pm.InstrumentationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageItemInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageUserState;
+import android.content.pm.PermissionGroupInfo;
+import android.content.pm.PermissionInfo;
+import android.content.pm.ProcessInfo;
+import android.content.pm.ProviderInfo;
+import android.content.pm.ServiceInfo;
+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.ParsedMainComponent;
+import android.content.pm.parsing.ComponentParseUtils.ParsedPermission;
+import android.content.pm.parsing.ComponentParseUtils.ParsedPermissionGroup;
+import android.content.pm.parsing.ComponentParseUtils.ParsedProcess;
+import android.content.pm.parsing.ComponentParseUtils.ParsedProvider;
+import android.content.pm.parsing.ComponentParseUtils.ParsedService;
+import android.content.pm.parsing.PackageInfoWithoutStateUtils;
+import android.os.UserHandle;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+
+import com.android.internal.util.ArrayUtils;
+import com.android.server.pm.PackageSetting;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
+
+import libcore.util.EmptyArray;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+
+/** @hide **/
+public class PackageInfoUtils {
+
+    @Nullable
+    public static PackageInfo generate(AndroidPackage pkg, int[] gids,
+            @PackageManager.PackageInfoFlags int flags, long firstInstallTime, long lastUpdateTime,
+            Set<String> grantedPermissions, PackageUserState state, int userId) {
+        PackageSetting pkgSetting = null;
+        return generateWithComponents(pkg, gids, flags, firstInstallTime, lastUpdateTime,
+                grantedPermissions, state, userId, null, pkgSetting);
+    }
+
+    @Nullable
+    public static PackageInfo generate(AndroidPackage pkg, ApexInfo apexInfo, int flags,
+            PackageSetting pkgSetting) {
+        return generateWithComponents(pkg, EmptyArray.INT, flags, 0, 0, Collections.emptySet(),
+                new PackageUserState(), UserHandle.getCallingUserId(), apexInfo, pkgSetting);
+    }
+
+    private static PackageInfo generateWithComponents(AndroidPackage pkg, int[] gids,
+            @PackageManager.PackageInfoFlags int flags, long firstInstallTime, long lastUpdateTime,
+            Set<String> grantedPermissions, PackageUserState state, int userId,
+            @Nullable ApexInfo apexInfo, @Nullable PackageSetting pkgSetting) {
+        ApplicationInfo applicationInfo = generateApplicationInfo(pkg, flags, state, userId);
+        if (applicationInfo == null) {
+            return null;
+        }
+
+        PackageInfo info = PackageInfoWithoutStateUtils.generateWithoutComponents(pkg, gids, flags,
+                firstInstallTime, lastUpdateTime, grantedPermissions, state, userId, apexInfo,
+                applicationInfo);
+        if (info == null) {
+            return null;
+        }
+
+        info.isStub = pkg.isStub();
+        info.coreApp = pkg.isCoreApp();
+
+        if ((flags & PackageManager.GET_ACTIVITIES) != 0) {
+            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.getName())) {
+                            continue;
+                        }
+                        res[num++] = generateActivityInfo(pkg, a, flags, state,
+                                applicationInfo, userId, pkgSetting);
+                    }
+                }
+                info.activities = ArrayUtils.trimToSize(res, num);
+            }
+        }
+        if ((flags & PackageManager.GET_RECEIVERS) != 0) {
+            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, pkgSetting);
+                    }
+                }
+                info.receivers = ArrayUtils.trimToSize(res, num);
+            }
+        }
+        if ((flags & PackageManager.GET_SERVICES) != 0) {
+            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 ParsedService s = pkg.getServices().get(i);
+                    if (state.isMatch(pkg.isSystem(), pkg.isEnabled(), s, flags)) {
+                        res[num++] = generateServiceInfo(pkg, s, flags, state, applicationInfo,
+                                userId, pkgSetting);
+                    }
+                }
+                info.services = ArrayUtils.trimToSize(res, num);
+            }
+        }
+        if ((flags & PackageManager.GET_PROVIDERS) != 0) {
+            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 ParsedProvider pr = pkg.getProviders()
+                            .get(i);
+                    if (state.isMatch(pkg.isSystem(), pkg.isEnabled(), pr, flags)) {
+                        res[num++] = generateProviderInfo(pkg, pr, flags, state, applicationInfo,
+                                userId, pkgSetting);
+                    }
+                }
+                info.providers = ArrayUtils.trimToSize(res, num);
+            }
+        }
+        if ((flags & PackageManager.GET_INSTRUMENTATION) != 0) {
+            int N = pkg.getInstrumentations().size();
+            if (N > 0) {
+                info.instrumentation = new InstrumentationInfo[N];
+                for (int i = 0; i < N; i++) {
+                    info.instrumentation[i] = generateInstrumentationInfo(
+                            pkg.getInstrumentations().get(i), pkg, flags, userId);
+                }
+            }
+        }
+
+        return info;
+    }
+
+    @Nullable
+    public static ApplicationInfo generateApplicationInfo(AndroidPackage pkg,
+            @PackageManager.ApplicationInfoFlags int flags, PackageUserState state, int userId) {
+        PackageSetting pkgSetting = null;
+        // TODO(b/135203078): Consider cases where we don't have a PkgSetting
+        if (pkg == null) {
+            return null;
+        }
+
+        if (!checkUseInstalledOrHidden(pkg, pkgSetting, state, flags)
+                || !AndroidPackageUtils.isMatchForSystemOnly(pkg, flags)) {
+            return null;
+        }
+
+        ApplicationInfo info = PackageInfoWithoutStateUtils.generateApplicationInfo(pkg, flags,
+                state, userId);
+        if (info == null) {
+            return null;
+        }
+
+        info.flags |= appInfoFlags(pkg, pkgSetting);
+        info.privateFlags |= appInfoPrivateFlags(pkg, pkgSetting);
+        return info;
+    }
+
+    @Nullable
+    public static ActivityInfo generateActivityInfo(AndroidPackage pkg, ParsedActivity a,
+            @PackageManager.ComponentInfoFlags int flags, PackageUserState state, int userId) {
+        PackageSetting pkgSetting = null;
+        return generateActivityInfo(pkg, a, flags, state, null, userId, pkgSetting);
+    }
+
+    @Nullable
+    private static ActivityInfo generateActivityInfo(AndroidPackage pkg, ParsedActivity a,
+            @PackageManager.ComponentInfoFlags int flags, PackageUserState state,
+            @Nullable ApplicationInfo applicationInfo, int userId,
+            @Nullable PackageSetting pkgSetting) {
+        if (a == null) return null;
+        if (!checkUseInstalledOrHidden(pkg, pkgSetting, state, flags)) {
+            return null;
+        }
+        if (applicationInfo == null) {
+            applicationInfo = generateApplicationInfo(pkg, flags, state, userId);
+        }
+        ActivityInfo info = PackageInfoWithoutStateUtils.generateActivityInfo(pkg, a, flags, state,
+                applicationInfo, userId);
+        if (info == null) {
+            return null;
+        }
+
+        assignSharedFieldsForComponentInfo(info, a, pkgSetting);
+        return info;
+    }
+
+    @Nullable
+    public static ServiceInfo generateServiceInfo(AndroidPackage pkg, ParsedService s,
+            @PackageManager.ComponentInfoFlags int flags, PackageUserState state, int userId) {
+        PackageSetting pkgSetting = null;
+        return generateServiceInfo(pkg, s, flags, state, null, userId, pkgSetting);
+    }
+
+    @Nullable
+    private static ServiceInfo generateServiceInfo(AndroidPackage pkg, ParsedService s,
+            @PackageManager.ComponentInfoFlags int flags, PackageUserState state,
+            @Nullable ApplicationInfo applicationInfo, int userId,
+            @Nullable PackageSetting pkgSetting) {
+        if (s == null) return null;
+        if (!checkUseInstalledOrHidden(pkg, pkgSetting, state, flags)) {
+            return null;
+        }
+        if (applicationInfo == null) {
+            applicationInfo = generateApplicationInfo(pkg, flags, state, userId);
+        }
+        ServiceInfo info = PackageInfoWithoutStateUtils.generateServiceInfo(pkg, s, flags, state,
+                applicationInfo, userId);
+        if (info == null) {
+            return null;
+        }
+
+        assignSharedFieldsForComponentInfo(info, s, pkgSetting);
+        return info;
+    }
+
+    @Nullable
+    public static ProviderInfo generateProviderInfo(AndroidPackage pkg, ParsedProvider p,
+            @PackageManager.ComponentInfoFlags int flags, PackageUserState state, int userId) {
+        PackageSetting pkgSetting = null;
+        return generateProviderInfo(pkg, p, flags, state, null, userId, pkgSetting);
+    }
+
+    @Nullable
+    private static ProviderInfo generateProviderInfo(AndroidPackage pkg, ParsedProvider p,
+            @PackageManager.ComponentInfoFlags int flags, PackageUserState state,
+            @Nullable ApplicationInfo applicationInfo, int userId,
+            @Nullable PackageSetting pkgSetting) {
+        if (p == null) return null;
+        if (!checkUseInstalledOrHidden(pkg, pkgSetting, state, flags)) {
+            return null;
+        }
+        if (applicationInfo == null) {
+            applicationInfo = generateApplicationInfo(pkg, flags, state, userId);
+        }
+        ProviderInfo info = PackageInfoWithoutStateUtils.generateProviderInfo(pkg, p, flags, state,
+                applicationInfo, userId);
+        if (info == null) {
+            return null;
+        }
+
+        assignSharedFieldsForComponentInfo(info, p, pkgSetting);
+        return info;
+    }
+
+    @Nullable
+    public static InstrumentationInfo generateInstrumentationInfo(ParsedInstrumentation i,
+            AndroidPackage pkg, @PackageManager.ComponentInfoFlags int flags, int userId) {
+        PackageSetting pkgSetting = null;
+        if (i == null) return null;
+
+        InstrumentationInfo info =
+                PackageInfoWithoutStateUtils.generateInstrumentationInfo(i, pkg, flags, userId);
+        if (info == null) {
+            return null;
+        }
+
+        // TODO(b/135203078): Add setting related state
+        info.primaryCpuAbi = pkg.getPrimaryCpuAbi();
+        info.secondaryCpuAbi = pkg.getSecondaryCpuAbi();
+        info.nativeLibraryDir = pkg.getNativeLibraryDir();
+        info.secondaryNativeLibraryDir = pkg.getSecondaryNativeLibraryDir();
+
+        assignStateFieldsForPackageItemInfo(info, i, pkgSetting);
+
+        return info;
+    }
+
+    // TODO(b/135203078): Determine if permission methods need to pass in a non-null PackageSetting
+    //  os that checkUseInstalledOrHidden filter can apply
+    @Nullable
+    public static PermissionInfo generatePermissionInfo(ParsedPermission p,
+            @PackageManager.ComponentInfoFlags int flags) {
+        // TODO(b/135203078): Remove null checks and make all usages @NonNull
+        if (p == null) return null;
+
+        // For now, permissions don't have state-adjustable fields; return directly
+        return PackageInfoWithoutStateUtils.generatePermissionInfo(p, flags);
+    }
+
+    @Nullable
+    public static PermissionGroupInfo generatePermissionGroupInfo(ParsedPermissionGroup pg,
+            @PackageManager.ComponentInfoFlags int flags) {
+        if (pg == null) return null;
+
+        // For now, permissions don't have state-adjustable fields; return directly
+        return PackageInfoWithoutStateUtils.generatePermissionGroupInfo(pg, flags);
+    }
+
+    @Nullable
+    public static ArrayMap<String, ProcessInfo> generateProcessInfo(
+            Map<String, ParsedProcess> procs, @PackageManager.ComponentInfoFlags int flags) {
+        if (procs == null) {
+            return null;
+        }
+
+        final int numProcs = procs.size();
+        ArrayMap<String, ProcessInfo> retProcs = new ArrayMap<>(numProcs);
+        for (String key : procs.keySet()) {
+            ParsedProcess proc = procs.get(key);
+            retProcs.put(proc.name, new ProcessInfo(proc.name,
+                    proc.deniedPermissions != null
+                            ? new ArraySet<>(proc.deniedPermissions) : null));
+        }
+        return retProcs;
+    }
+
+    /**
+     * 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,
+            PackageSetting pkgSetting, 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.isSystem()
+                && ((flags & PackageManager.MATCH_KNOWN_PACKAGES) != 0
+                || (flags & PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS) != 0));
+    }
+
+    private static void assignSharedFieldsForComponentInfo(@NonNull ComponentInfo componentInfo,
+            @NonNull ParsedMainComponent mainComponent, @Nullable PackageSetting pkgSetting) {
+        assignStateFieldsForPackageItemInfo(componentInfo, mainComponent, pkgSetting);
+        componentInfo.descriptionRes = mainComponent.descriptionRes;
+        componentInfo.directBootAware = mainComponent.isDirectBootAware();
+        componentInfo.enabled = mainComponent.isEnabled();
+        componentInfo.splitName = mainComponent.getSplitName();
+    }
+
+    private static void assignStateFieldsForPackageItemInfo(
+            @NonNull PackageItemInfo packageItemInfo, @NonNull ParsedComponent component,
+            @Nullable PackageSetting pkgSetting) {
+        // TODO(b/135203078): Add setting related state
+    }
+
+    @CheckResult
+    private static int flag(boolean hasFlag, int flag) {
+        return hasFlag ? flag : 0;
+    }
+
+    /** @see ApplicationInfo#flags */
+    public static int appInfoFlags(AndroidPackage pkg, @Nullable PackageSetting pkgSetting) {
+        // TODO(b/135203078): Add setting related state
+        // @formatter:off
+        return PackageInfoWithoutStateUtils.appInfoFlags(pkg)
+                | flag(pkg.isSystem(), ApplicationInfo.FLAG_SYSTEM)
+                | flag(pkg.isFactoryTest(), ApplicationInfo.FLAG_FACTORY_TEST)
+                | flag(pkg.isUpdatedSystemApp(), ApplicationInfo.FLAG_UPDATED_SYSTEM_APP);
+        // @formatter:on
+    }
+
+    /** @see ApplicationInfo#privateFlags */
+    public static int appInfoPrivateFlags(AndroidPackage pkg, @Nullable PackageSetting pkgSetting) {
+        // TODO(b/135203078): Add setting related state
+        // @formatter:off
+        return PackageInfoWithoutStateUtils.appInfoPrivateFlags(pkg)
+                | flag(pkg.isSystemExt(), ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT)
+                | flag(pkg.isPrivileged(), ApplicationInfo.PRIVATE_FLAG_PRIVILEGED)
+                | flag(pkg.isOem(), ApplicationInfo.PRIVATE_FLAG_OEM)
+                | flag(pkg.isVendor(), ApplicationInfo.PRIVATE_FLAG_VENDOR)
+                | flag(pkg.isProduct(), ApplicationInfo.PRIVATE_FLAG_PRODUCT)
+                | flag(pkg.isOdm(), ApplicationInfo.PRIVATE_FLAG_ODM)
+                | flag(pkg.isSignedWithPlatformKey(), ApplicationInfo.PRIVATE_FLAG_SIGNED_WITH_PLATFORM_KEY);
+        // @formatter:on
+    }
+}
diff --git a/services/core/java/com/android/server/pm/parsing/PackageParser2.java b/services/core/java/com/android/server/pm/parsing/PackageParser2.java
new file mode 100644
index 0000000..804f110
--- /dev/null
+++ b/services/core/java/com/android/server/pm/parsing/PackageParser2.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2020 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.parsing;
+
+import android.annotation.AnyThread;
+import android.annotation.Nullable;
+import android.content.pm.PackageParser;
+import android.content.pm.parsing.ParsingPackage;
+import android.content.pm.parsing.ParsingPackageUtils;
+import android.content.res.TypedArray;
+import android.os.Build;
+import android.os.SystemClock;
+import android.util.DisplayMetrics;
+import android.util.Slog;
+
+import com.android.server.pm.parsing.pkg.PackageImpl;
+import com.android.server.pm.parsing.pkg.ParsedPackage;
+
+import java.io.File;
+
+/**
+ * The v2 of {@link PackageParser} for use when parsing is initiated in the server and must
+ * contain state contained by the server.
+ */
+public class PackageParser2 {
+
+    private static final String TAG = "PackageParser2";
+
+    private static final boolean LOG_PARSE_TIMINGS = Build.IS_DEBUGGABLE;
+    private static final int LOG_PARSE_TIMINGS_THRESHOLD_MS = 100;
+
+    private ThreadLocal<ParsingPackageUtils.ParseResult> mSharedResult = ThreadLocal.withInitial(
+            ParsingPackageUtils.ParseResult::new);
+
+    private final String[] mSeparateProcesses;
+    private final boolean mOnlyCoreApps;
+    private final DisplayMetrics mDisplayMetrics;
+    private final Callback mCallback;
+
+    @Nullable
+    protected PackageCacher mCacher;
+
+    /**
+     * @param onlyCoreApps Flag indicating this parser should only consider apps with
+     *                     {@code coreApp} manifest attribute to be valid apps. This is useful when
+     *                     creating a minimalist boot environment.
+     */
+    public PackageParser2(String[] separateProcesses, boolean onlyCoreApps,
+            DisplayMetrics displayMetrics, @Nullable File cacheDir, Callback callback) {
+        mSeparateProcesses = separateProcesses;
+        mOnlyCoreApps = onlyCoreApps;
+
+        if (displayMetrics == null) {
+            mDisplayMetrics = new DisplayMetrics();
+            mDisplayMetrics.setToDefaults();
+        } else {
+            mDisplayMetrics = displayMetrics;
+        }
+
+        mCacher = cacheDir == null ? null : new PackageCacher(cacheDir);
+        // TODO(b/135203078): Remove nullability of callback
+        mCallback = callback != null ? callback : new Callback() {
+            @Override
+            public boolean hasFeature(String feature) {
+                return false;
+            }
+        };
+    }
+
+    /**
+     * TODO(b/135203078): Document new package parsing
+     */
+    @AnyThread
+    public ParsedPackage parsePackage(File packageFile, int flags, boolean useCaches)
+            throws PackageParser.PackageParserException {
+        if (useCaches && mCacher != null) {
+            ParsedPackage parsed = mCacher.getCachedResult(packageFile, flags);
+            if (parsed != null) {
+                return parsed;
+            }
+        }
+
+        long parseTime = LOG_PARSE_TIMINGS ? SystemClock.uptimeMillis() : 0;
+        ParsingPackageUtils.ParseInput parseInput = mSharedResult.get().reset();
+        ParsedPackage parsed = (ParsedPackage) ParsingPackageUtils.parsePackage(parseInput,
+                mSeparateProcesses, mCallback, mDisplayMetrics, mOnlyCoreApps, packageFile, flags)
+                .hideAsParsed();
+
+        long cacheTime = LOG_PARSE_TIMINGS ? SystemClock.uptimeMillis() : 0;
+        if (mCacher != null) {
+            mCacher.cacheResult(packageFile, flags, parsed);
+        }
+        if (LOG_PARSE_TIMINGS) {
+            parseTime = cacheTime - parseTime;
+            cacheTime = SystemClock.uptimeMillis() - cacheTime;
+            if (parseTime + cacheTime > LOG_PARSE_TIMINGS_THRESHOLD_MS) {
+                Slog.i(TAG, "Parse times for '" + packageFile + "': parse=" + parseTime
+                        + "ms, update_cache=" + cacheTime + " ms");
+            }
+        }
+
+        return parsed;
+    }
+
+    public static abstract class Callback implements ParsingPackageUtils.Callback {
+
+        @Override
+        public final ParsingPackage startParsingPackage(String packageName, String baseCodePath,
+                String codePath, TypedArray manifestArray, boolean isCoreApp) {
+            return PackageImpl.forParsing(packageName, baseCodePath, codePath, manifestArray,
+                    isCoreApp);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackage.java b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackage.java
index 239cf9d..d0ec969 100644
--- a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackage.java
+++ b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackage.java
@@ -187,7 +187,7 @@
     @NonNull
     List<ParsedPermissionGroup> getPermissionGroups();
 
-    @Nullable
+    @NonNull
     List<ParsedFeature> getFeatures();
 
     /**
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 36697f9..e1d1a1a 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -3612,7 +3612,7 @@
             return EmptyArray.INT;
         }
         for (AndroidPackage pkg : pkgList) {
-            if (pkg.getRequestedPermissions() == null) {
+            if (pkg.getRequestedPermissions().isEmpty()) {
                 continue;
             }
             final int requestedPermCount = pkg.getRequestedPermissions().size();
@@ -4246,7 +4246,7 @@
     }
 
     private static boolean hasPermission(AndroidPackage pkg, String permName) {
-        if (pkg.getPermissions() == null) {
+        if (pkg.getPermissions().isEmpty()) {
             return false;
         }
 
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 da5986f7..20f3f3e 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ParallelPackageParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ParallelPackageParserTest.java
@@ -17,11 +17,13 @@
 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;
 
+import com.android.server.pm.parsing.PackageParser2;
+import com.android.server.pm.parsing.pkg.ParsedPackage;
+
 import junit.framework.Assert;
 
 import org.junit.Before;
@@ -44,7 +46,7 @@
 
     @Before
     public void setUp() {
-        mParser = new TestParallelPackageParser(new PackageParser(),
+        mParser = new TestParallelPackageParser(new PackageParser2(null, false, null, null, null),
                 ParallelPackageParser.makeExecutorService());
     }
 
@@ -72,7 +74,7 @@
 
     private class TestParallelPackageParser extends ParallelPackageParser {
 
-        TestParallelPackageParser(PackageParser packageParser, ExecutorService executorService) {
+        TestParallelPackageParser(PackageParser2 packageParser, ExecutorService executorService) {
             super(packageParser, executorService);
         }